summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBret Curtis <psi29a@gmail.com>2013-11-15 13:24:12 +0100
committerBret Curtis <psi29a@gmail.com>2013-11-15 13:24:12 +0100
commit4dca3c5ce1400f655b3a7184e21d23460447a521 (patch)
tree27b89b26b8fa039d70b2b8bd7cf77fdd91bf2ec8
parent9a2b6c69b6064cd7e6fe12f901b11521afbc6dfe (diff)
Imported Upstream version 0.27.0upstream/0.27.0
-rw-r--r--.gitignore53
-rw-r--r--CMakeLists.txt53
-rw-r--r--Daedric Font License.txt10
-rw-r--r--apps/esmtool/.gitignore6
-rw-r--r--apps/esmtool/esmtool.cpp4
-rw-r--r--apps/launcher/CMakeLists.txt13
-rw-r--r--apps/launcher/datafilespage.cpp585
-rw-r--r--apps/launcher/datafilespage.hpp156
-rw-r--r--apps/launcher/graphicspage.cpp35
-rw-r--r--apps/launcher/graphicspage.hpp85
-rw-r--r--apps/launcher/main.cpp9
-rw-r--r--apps/launcher/maindialog.cpp109
-rw-r--r--apps/launcher/maindialog.hpp78
-rw-r--r--apps/launcher/playpage.cpp16
-rw-r--r--apps/launcher/playpage.hpp31
-rw-r--r--apps/launcher/settings/gamesettings.cpp42
-rw-r--r--apps/launcher/settings/gamesettings.hpp82
-rw-r--r--apps/launcher/settings/graphicssettings.cpp6
-rw-r--r--apps/launcher/settings/graphicssettings.hpp16
-rw-r--r--apps/launcher/settings/launchersettings.cpp15
-rw-r--r--apps/launcher/settings/launchersettings.hpp20
-rw-r--r--apps/launcher/settings/settingsbase.hpp144
-rw-r--r--apps/launcher/textslotmsgbox.cpp2
-rw-r--r--apps/launcher/textslotmsgbox.hpp14
-rw-r--r--apps/launcher/unshieldthread.cpp204
-rw-r--r--apps/launcher/unshieldthread.hpp65
-rw-r--r--apps/launcher/utils/checkablemessagebox.cpp159
-rw-r--r--apps/launcher/utils/checkablemessagebox.hpp138
-rw-r--r--apps/launcher/utils/lineedit.cpp (renamed from components/fileorderlist/utils/lineedit.cpp)15
-rw-r--r--apps/launcher/utils/lineedit.hpp (renamed from components/fileorderlist/utils/lineedit.hpp)9
-rw-r--r--apps/launcher/utils/profilescombobox.cpp (renamed from components/fileorderlist/utils/profilescombobox.cpp)31
-rw-r--r--apps/launcher/utils/profilescombobox.hpp47
-rw-r--r--apps/launcher/utils/textinputdialog.cpp42
-rw-r--r--apps/launcher/utils/textinputdialog.hpp40
-rw-r--r--apps/mwiniimporter/importer.cpp25
-rw-r--r--apps/opencs/CMakeLists.txt61
-rw-r--r--apps/opencs/editor.cpp161
-rw-r--r--apps/opencs/editor.hpp24
-rw-r--r--apps/opencs/main.cpp27
-rw-r--r--apps/opencs/model/doc/document.cpp204
-rw-r--r--apps/opencs/model/doc/document.hpp31
-rw-r--r--apps/opencs/model/doc/documentmanager.cpp24
-rw-r--r--apps/opencs/model/doc/documentmanager.hpp14
-rw-r--r--apps/opencs/model/doc/operation.cpp (renamed from apps/opencs/model/tools/operation.cpp)61
-rw-r--r--apps/opencs/model/doc/operation.hpp (renamed from apps/opencs/model/tools/operation.hpp)21
-rw-r--r--apps/opencs/model/doc/saving.cpp74
-rw-r--r--apps/opencs/model/doc/saving.hpp27
-rw-r--r--apps/opencs/model/doc/savingstages.cpp161
-rw-r--r--apps/opencs/model/doc/savingstages.hpp172
-rw-r--r--apps/opencs/model/doc/savingstate.cpp65
-rw-r--r--apps/opencs/model/doc/savingstate.hpp50
-rw-r--r--apps/opencs/model/doc/stage.cpp4
-rw-r--r--apps/opencs/model/doc/stage.hpp (renamed from apps/opencs/model/tools/stage.hpp)8
-rw-r--r--apps/opencs/model/filter/parser.cpp74
-rw-r--r--apps/opencs/model/filter/textnode.cpp27
-rw-r--r--apps/opencs/model/filter/valuenode.cpp52
-rw-r--r--apps/opencs/model/filter/valuenode.hpp15
-rw-r--r--apps/opencs/model/tools/birthsigncheck.cpp7
-rw-r--r--apps/opencs/model/tools/birthsigncheck.hpp4
-rw-r--r--apps/opencs/model/tools/classcheck.cpp7
-rw-r--r--apps/opencs/model/tools/classcheck.hpp4
-rw-r--r--apps/opencs/model/tools/factioncheck.cpp7
-rw-r--r--apps/opencs/model/tools/factioncheck.hpp4
-rw-r--r--apps/opencs/model/tools/mandatoryid.hpp4
-rw-r--r--apps/opencs/model/tools/racecheck.cpp7
-rw-r--r--apps/opencs/model/tools/racecheck.hpp4
-rw-r--r--apps/opencs/model/tools/regioncheck.cpp7
-rw-r--r--apps/opencs/model/tools/regioncheck.hpp4
-rw-r--r--apps/opencs/model/tools/skillcheck.cpp7
-rw-r--r--apps/opencs/model/tools/skillcheck.hpp4
-rw-r--r--apps/opencs/model/tools/soundcheck.cpp7
-rw-r--r--apps/opencs/model/tools/soundcheck.hpp4
-rw-r--r--apps/opencs/model/tools/spellcheck.cpp7
-rw-r--r--apps/opencs/model/tools/spellcheck.hpp4
-rw-r--r--apps/opencs/model/tools/stage.cpp4
-rw-r--r--apps/opencs/model/tools/tools.cpp22
-rw-r--r--apps/opencs/model/tools/tools.hpp17
-rw-r--r--apps/opencs/model/tools/verifier.cpp7
-rw-r--r--apps/opencs/model/tools/verifier.hpp17
-rw-r--r--apps/opencs/model/world/collection.hpp20
-rw-r--r--apps/opencs/model/world/collectionbase.cpp25
-rw-r--r--apps/opencs/model/world/collectionbase.hpp14
-rw-r--r--apps/opencs/model/world/columnbase.hpp3
-rw-r--r--apps/opencs/model/world/columnimp.hpp132
-rw-r--r--apps/opencs/model/world/columns.cpp124
-rw-r--r--apps/opencs/model/world/columns.hpp210
-rw-r--r--apps/opencs/model/world/data.cpp214
-rw-r--r--apps/opencs/model/world/data.hpp60
-rw-r--r--apps/opencs/model/world/idcollection.hpp83
-rw-r--r--apps/opencs/model/world/idtable.cpp15
-rw-r--r--apps/opencs/model/world/refcollection.cpp4
-rw-r--r--apps/opencs/model/world/refcollection.hpp6
-rw-r--r--apps/opencs/model/world/refidcollection.cpp10
-rw-r--r--apps/opencs/model/world/refidcollection.hpp12
-rw-r--r--apps/opencs/model/world/refiddata.cpp35
-rw-r--r--apps/opencs/model/world/refiddata.hpp37
-rw-r--r--apps/opencs/model/world/scriptcontext.cpp24
-rw-r--r--apps/opencs/model/world/scriptcontext.hpp13
-rw-r--r--apps/opencs/model/world/universalid.cpp68
-rw-r--r--apps/opencs/model/world/universalid.hpp15
-rw-r--r--apps/opencs/ocspropertywidget.cpp6
-rw-r--r--apps/opencs/ocspropertywidget.hpp18
-rw-r--r--apps/opencs/view/doc/adjusterwidget.cpp115
-rw-r--r--apps/opencs/view/doc/adjusterwidget.hpp56
-rw-r--r--apps/opencs/view/doc/filedialog.cpp304
-rw-r--r--apps/opencs/view/doc/filedialog.hpp92
-rw-r--r--apps/opencs/view/doc/filewidget.cpp58
-rw-r--r--apps/opencs/view/doc/filewidget.hpp42
-rw-r--r--apps/opencs/view/doc/newgame.cpp68
-rw-r--r--apps/opencs/view/doc/newgame.hpp47
-rw-r--r--apps/opencs/view/doc/startup.cpp112
-rw-r--r--apps/opencs/view/doc/startup.hpp24
-rw-r--r--apps/opencs/view/doc/view.cpp48
-rw-r--r--apps/opencs/view/doc/view.hpp12
-rw-r--r--apps/opencs/view/doc/viewmanager.cpp105
-rw-r--r--apps/opencs/view/doc/viewmanager.hpp6
-rw-r--r--apps/opencs/view/filter/filtercreator.cpp16
-rw-r--r--apps/opencs/view/filter/filtercreator.hpp2
-rw-r--r--apps/opencs/view/settings/usersettingsdialog.cpp16
-rw-r--r--apps/opencs/view/tools/reportsubview.cpp12
-rw-r--r--apps/opencs/view/tools/reportsubview.hpp8
-rw-r--r--apps/opencs/view/world/dialoguecreator.cpp35
-rw-r--r--apps/opencs/view/world/dialoguecreator.hpp41
-rw-r--r--apps/opencs/view/world/enumdelegate.cpp12
-rw-r--r--apps/opencs/view/world/enumdelegate.hpp3
-rwxr-xr-xapps/opencs/view/world/idtypedelegate.cpp46
-rwxr-xr-xapps/opencs/view/world/idtypedelegate.hpp (renamed from apps/opencs/view/world/refidtypedelegate.hpp)20
-rw-r--r--apps/opencs/view/world/recordstatusdelegate.cpp18
-rwxr-xr-xapps/opencs/view/world/refidtypedelegate.cpp60
-rw-r--r--apps/opencs/view/world/refrecordtypedelegate.cpp25
-rw-r--r--apps/opencs/view/world/refrecordtypedelegate.hpp58
-rw-r--r--apps/opencs/view/world/scenesubview.cpp82
-rw-r--r--apps/opencs/view/world/scenesubview.hpp37
-rw-r--r--apps/opencs/view/world/scenetool.cpp17
-rw-r--r--apps/opencs/view/world/scenetool.hpp27
-rw-r--r--apps/opencs/view/world/scenetoolbar.cpp29
-rw-r--r--apps/opencs/view/world/scenetoolbar.hpp29
-rw-r--r--apps/opencs/view/world/scenetoolmode.cpp56
-rw-r--r--apps/opencs/view/world/scenetoolmode.hpp42
-rw-r--r--apps/opencs/view/world/scripthighlighter.cpp23
-rw-r--r--apps/opencs/view/world/scripthighlighter.hpp9
-rw-r--r--apps/opencs/view/world/scriptsubview.cpp31
-rw-r--r--apps/opencs/view/world/scriptsubview.hpp14
-rw-r--r--apps/opencs/view/world/subviews.cpp9
-rw-r--r--apps/opencs/view/world/table.cpp28
-rw-r--r--apps/opencs/view/world/vartypedelegate.cpp31
-rw-r--r--apps/openmw/CMakeLists.txt5
-rw-r--r--apps/openmw/engine.cpp47
-rw-r--r--apps/openmw/engine.hpp15
-rw-r--r--apps/openmw/main.cpp36
-rw-r--r--apps/openmw/mwbase/world.hpp11
-rw-r--r--apps/openmw/mwclass/light.cpp43
-rw-r--r--apps/openmw/mwclass/light.hpp8
-rw-r--r--apps/openmw/mwclass/npc.cpp39
-rw-r--r--apps/openmw/mwclass/npc.hpp3
-rw-r--r--apps/openmw/mwgui/fontloader.cpp55
-rw-r--r--apps/openmw/mwgui/hud.cpp23
-rw-r--r--apps/openmw/mwgui/hud.hpp5
-rw-r--r--apps/openmw/mwgui/loadingscreen.cpp18
-rw-r--r--apps/openmw/mwgui/loadingscreen.hpp2
-rw-r--r--apps/openmw/mwgui/mainmenu.cpp3
-rw-r--r--apps/openmw/mwgui/messagebox.cpp15
-rw-r--r--apps/openmw/mwgui/messagebox.hpp1
-rw-r--r--apps/openmw/mwgui/settingswindow.cpp4
-rw-r--r--apps/openmw/mwgui/spellicons.cpp34
-rw-r--r--apps/openmw/mwgui/widgets.cpp40
-rw-r--r--apps/openmw/mwgui/windowmanagerimp.cpp33
-rw-r--r--apps/openmw/mwinput/inputmanagerimp.cpp47
-rw-r--r--apps/openmw/mwmechanics/actors.cpp104
-rw-r--r--apps/openmw/mwmechanics/actors.hpp2
-rw-r--r--apps/openmw/mwmechanics/character.cpp55
-rw-r--r--apps/openmw/mwmechanics/character.hpp5
-rw-r--r--apps/openmw/mwmechanics/magiceffects.cpp3
-rw-r--r--apps/openmw/mwrender/.gitignore1
-rw-r--r--apps/openmw/mwrender/camera.cpp6
-rw-r--r--apps/openmw/mwrender/camera.hpp6
-rw-r--r--apps/openmw/mwrender/npcanimation.cpp13
-rw-r--r--apps/openmw/mwrender/npcanimation.hpp7
-rw-r--r--apps/openmw/mwrender/renderingmanager.cpp16
-rw-r--r--apps/openmw/mwscript/docs/vmformat.txt5
-rw-r--r--apps/openmw/mwscript/miscextensions.cpp29
-rw-r--r--apps/openmw/mwscript/statsextensions.cpp3
-rw-r--r--apps/openmw/mwworld/class.cpp15
-rw-r--r--apps/openmw/mwworld/class.hpp11
-rw-r--r--apps/openmw/mwworld/containerstore.cpp2
-rw-r--r--apps/openmw/mwworld/contentloader.hpp36
-rw-r--r--apps/openmw/mwworld/esmloader.cpp31
-rw-r--r--apps/openmw/mwworld/esmloader.hpp34
-rw-r--r--apps/openmw/mwworld/esmstore.cpp6
-rw-r--r--apps/openmw/mwworld/omwloader.cpp17
-rw-r--r--apps/openmw/mwworld/omwloader.hpp21
-rw-r--r--apps/openmw/mwworld/store.hpp24
-rw-r--r--apps/openmw/mwworld/worldimp.cpp141
-rw-r--r--apps/openmw/mwworld/worldimp.hpp29
-rw-r--r--components/CMakeLists.txt16
-rw-r--r--components/bsa/tests/.gitignore3
-rw-r--r--components/compiler/extensions0.cpp4
-rw-r--r--components/compiler/opcodes.hpp3
-rw-r--r--components/contentselector/model/contentmodel.cpp616
-rw-r--r--components/contentselector/model/contentmodel.hpp77
-rw-r--r--components/contentselector/model/esmfile.cpp137
-rw-r--r--components/contentselector/model/esmfile.hpp86
-rw-r--r--components/contentselector/model/modelitem.cpp69
-rw-r--r--components/contentselector/model/modelitem.hpp39
-rw-r--r--components/contentselector/model/naturalsort.cpp (renamed from components/fileorderlist/utils/naturalsort.cpp)0
-rw-r--r--components/contentselector/model/naturalsort.hpp11
-rw-r--r--components/contentselector/view/combobox.cpp39
-rw-r--r--components/contentselector/view/combobox.hpp30
-rw-r--r--components/contentselector/view/contentselector.cpp203
-rw-r--r--components/contentselector/view/contentselector.hpp68
-rw-r--r--components/esm/aipackage.cpp4
-rw-r--r--components/esm/aipackage.hpp2
-rw-r--r--components/esm/cellref.cpp2
-rw-r--r--components/esm/cellref.hpp2
-rw-r--r--components/esm/defs.hpp6
-rw-r--r--components/esm/effectlist.cpp4
-rw-r--r--components/esm/effectlist.hpp4
-rw-r--r--components/esm/esmreader.hpp2
-rw-r--r--components/esm/esmwriter.cpp287
-rw-r--r--components/esm/esmwriter.hpp183
-rw-r--r--components/esm/filter.cpp5
-rw-r--r--components/esm/filter.hpp4
-rw-r--r--components/esm/loadacti.cpp5
-rw-r--r--components/esm/loadacti.hpp4
-rw-r--r--components/esm/loadalch.cpp5
-rw-r--r--components/esm/loadalch.hpp4
-rw-r--r--components/esm/loadappa.cpp5
-rw-r--r--components/esm/loadappa.hpp4
-rw-r--r--components/esm/loadarmo.cpp9
-rw-r--r--components/esm/loadarmo.hpp6
-rw-r--r--components/esm/loadbody.cpp5
-rw-r--r--components/esm/loadbody.hpp4
-rw-r--r--components/esm/loadbook.cpp4
-rw-r--r--components/esm/loadbook.hpp4
-rw-r--r--components/esm/loadbsgn.cpp4
-rw-r--r--components/esm/loadbsgn.hpp4
-rw-r--r--components/esm/loadcell.cpp8
-rw-r--r--components/esm/loadcell.hpp5
-rw-r--r--components/esm/loadclas.cpp4
-rw-r--r--components/esm/loadclas.hpp4
-rw-r--r--components/esm/loadclot.cpp4
-rw-r--r--components/esm/loadclot.hpp4
-rw-r--r--components/esm/loadcont.cpp9
-rw-r--r--components/esm/loadcont.hpp6
-rw-r--r--components/esm/loadcrea.cpp5
-rw-r--r--components/esm/loadcrea.hpp4
-rw-r--r--components/esm/loadcrec.hpp6
-rw-r--r--components/esm/loaddial.cpp9
-rw-r--r--components/esm/loaddial.hpp7
-rw-r--r--components/esm/loaddoor.cpp4
-rw-r--r--components/esm/loaddoor.hpp4
-rw-r--r--components/esm/loadench.cpp4
-rw-r--r--components/esm/loadench.hpp4
-rw-r--r--components/esm/loadfact.cpp7
-rw-r--r--components/esm/loadfact.hpp4
-rw-r--r--components/esm/loadglob.cpp6
-rw-r--r--components/esm/loadglob.hpp4
-rw-r--r--components/esm/loadgmst.cpp6
-rw-r--r--components/esm/loadgmst.hpp6
-rw-r--r--components/esm/loadinfo.cpp6
-rw-r--r--components/esm/loadinfo.hpp4
-rw-r--r--components/esm/loadingr.cpp4
-rw-r--r--components/esm/loadingr.hpp4
-rw-r--r--components/esm/loadland.cpp20
-rw-r--r--components/esm/loadland.hpp4
-rw-r--r--components/esm/loadlevlist.cpp9
-rw-r--r--components/esm/loadlevlist.hpp6
-rw-r--r--components/esm/loadligh.cpp4
-rw-r--r--components/esm/loadligh.hpp4
-rw-r--r--components/esm/loadlock.cpp4
-rw-r--r--components/esm/loadlock.hpp4
-rw-r--r--components/esm/loadltex.cpp4
-rw-r--r--components/esm/loadltex.hpp4
-rw-r--r--components/esm/loadmgef.cpp30
-rw-r--r--components/esm/loadmgef.hpp14
-rw-r--r--components/esm/loadmisc.cpp4
-rw-r--r--components/esm/loadmisc.hpp4
-rw-r--r--components/esm/loadnpc.cpp6
-rw-r--r--components/esm/loadnpc.hpp4
-rw-r--r--components/esm/loadnpcc.hpp4
-rw-r--r--components/esm/loadpgrd.cpp12
-rw-r--r--components/esm/loadpgrd.hpp4
-rw-r--r--components/esm/loadprob.cpp4
-rw-r--r--components/esm/loadprob.hpp4
-rw-r--r--components/esm/loadrace.cpp5
-rw-r--r--components/esm/loadrace.hpp4
-rw-r--r--components/esm/loadregn.cpp6
-rw-r--r--components/esm/loadregn.hpp4
-rw-r--r--components/esm/loadrepa.cpp4
-rw-r--r--components/esm/loadrepa.hpp4
-rw-r--r--components/esm/loadscpt.cpp9
-rw-r--r--components/esm/loadscpt.hpp4
-rw-r--r--components/esm/loadskil.cpp5
-rw-r--r--components/esm/loadskil.hpp4
-rw-r--r--components/esm/loadsndg.cpp4
-rw-r--r--components/esm/loadsndg.hpp4
-rw-r--r--components/esm/loadsoun.cpp4
-rw-r--r--components/esm/loadsoun.hpp4
-rw-r--r--components/esm/loadspel.cpp4
-rw-r--r--components/esm/loadspel.hpp4
-rw-r--r--components/esm/loadsscr.cpp4
-rw-r--r--components/esm/loadsscr.hpp4
-rw-r--r--components/esm/loadstat.cpp4
-rw-r--r--components/esm/loadstat.hpp4
-rw-r--r--components/esm/loadtes3.cpp2
-rw-r--r--components/esm/loadtes3.hpp2
-rw-r--r--components/esm/loadweap.cpp4
-rw-r--r--components/esm/loadweap.hpp4
-rw-r--r--components/esm/spelllist.cpp4
-rw-r--r--components/esm/spelllist.hpp2
-rw-r--r--components/esm/variant.hpp2
-rw-r--r--components/esm/variantimp.cpp2
-rw-r--r--components/fileorderlist/model/datafilesmodel.cpp445
-rw-r--r--components/fileorderlist/model/datafilesmodel.hpp66
-rw-r--r--components/fileorderlist/model/esm/esmfile.cpp50
-rw-r--r--components/fileorderlist/model/esm/esmfile.hpp54
-rw-r--r--components/fileorderlist/model/modelitem.cpp57
-rw-r--r--components/fileorderlist/model/modelitem.hpp32
-rw-r--r--components/fileorderlist/model/pluginsproxymodel.cpp17
-rw-r--r--components/fileorderlist/model/pluginsproxymodel.hpp18
-rw-r--r--components/fileorderlist/utils/comboboxlineedit.cpp35
-rw-r--r--components/fileorderlist/utils/comboboxlineedit.hpp35
-rw-r--r--components/fileorderlist/utils/naturalsort.hpp11
-rw-r--r--components/fileorderlist/utils/profilescombobox.hpp30
-rw-r--r--components/files/configurationmanager.cpp14
-rw-r--r--components/files/configurationmanager.hpp4
-rw-r--r--components/misc/tests/.gitignore1
-rw-r--r--components/nif/.gitignore1
-rw-r--r--components/nif/niffile.cpp2
-rw-r--r--components/nif/tests/.gitignore5
-rw-r--r--components/nifogre/tests/.gitignore5
-rw-r--r--components/to_utf8/.gitignore1
-rw-r--r--components/to_utf8/tests/.gitignore1
-rw-r--r--credits.txt3
-rw-r--r--extern/oics/CMakeLists.txt15
-rw-r--r--extern/sdl4ogre/sdlinputwrapper.cpp3
-rw-r--r--files/mac/opencs.icnsbin0 -> 50537 bytes
-rw-r--r--files/mygui/CMakeLists.txt1
-rw-r--r--files/mygui/Obliviontt.zipbin138502 -> 0 bytes
-rw-r--r--files/mygui/openmw_console.layout1
-rw-r--r--files/mygui/openmw_hud.layout1
-rw-r--r--files/mygui/openmw_progress.skin.xml9
-rw-r--r--files/opencs/GMST.pngbin0 -> 820 bytes
-rw-r--r--files/opencs/Info.pngbin0 -> 1234 bytes
-rw-r--r--files/opencs/LandTexture.pngbin0 -> 2662 bytes
-rw-r--r--files/opencs/PathGrid.pngbin0 -> 1297 bytes
-rw-r--r--[-rwxr-xr-x]files/opencs/activator.pngbin2297 -> 1913 bytes
-rw-r--r--files/opencs/added.pngbin862 -> 615 bytes
-rw-r--r--[-rwxr-xr-x]files/opencs/apparatus.pngbin1440 -> 1440 bytes
-rw-r--r--[-rwxr-xr-x]files/opencs/armor.pngbin1641 -> 1641 bytes
-rw-r--r--files/opencs/attribute.pngbin0 -> 1788 bytes
-rw-r--r--files/opencs/birthsign.pngbin0 -> 2454 bytes
-rw-r--r--files/opencs/body-part.pngbin0 -> 1248 bytes
-rw-r--r--[-rwxr-xr-x]files/opencs/book.pngbin1336 -> 1599 bytes
-rw-r--r--files/opencs/cell.pngbin0 -> 1403 bytes
-rw-r--r--files/opencs/class.pngbin0 -> 2283 bytes
-rw-r--r--[-rwxr-xr-x]files/opencs/clothing.pngbin1377 -> 1377 bytes
-rw-r--r--[-rwxr-xr-x]files/opencs/container.pngbin1526 -> 1526 bytes
-rw-r--r--[-rwxr-xr-x]files/opencs/creature.pngbin2297 -> 2297 bytes
-rw-r--r--files/opencs/defaultfiltersbin0 -> 10958 bytes
-rw-r--r--files/opencs/dialogoue-info.pngbin0 -> 1851 bytes
-rw-r--r--files/opencs/dialogoue-journal.pngbin0 -> 1991 bytes
-rw-r--r--files/opencs/dialogoue-regular.pngbin0 -> 1486 bytes
-rw-r--r--files/opencs/dialogue-greeting.pngbin0 -> 1948 bytes
-rw-r--r--files/opencs/dialogue-persuasion.pngbin0 -> 1987 bytes
-rw-r--r--files/opencs/dialogue-speech.pngbin0 -> 1987 bytes
-rw-r--r--[-rwxr-xr-x]files/opencs/door.pngbin1627 -> 1627 bytes
-rw-r--r--files/opencs/enchantment.pngbin0 -> 1812 bytes
-rw-r--r--files/opencs/faction.pngbin0 -> 1858 bytes
-rw-r--r--files/opencs/filter.pngbin0 -> 1375 bytes
-rw-r--r--files/opencs/globvar.pngbin0 -> 2394 bytes
-rw-r--r--[-rwxr-xr-x]files/opencs/ingredient.pngbin1444 -> 1384 bytes
-rw-r--r--files/opencs/land.pngbin0 -> 1220 bytes
-rw-r--r--files/opencs/landpaint.pngbin0 -> 1361 bytes
-rw-r--r--[-rwxr-xr-x]files/opencs/leveled-creature.pngbin2150 -> 2150 bytes
-rw-r--r--[-rwxr-xr-x]files/opencs/light.pngbin747 -> 1199 bytes
-rw-r--r--[-rwxr-xr-x]files/opencs/lockpick.pngbin671 -> 671 bytes
-rw-r--r--files/opencs/magic-effect.pngbin0 -> 1702 bytes
-rw-r--r--files/opencs/magicrabbit.pngbin0 -> 1820 bytes
-rw-r--r--files/opencs/map.pngbin0 -> 1477 bytes
-rw-r--r--[-rwxr-xr-x]files/opencs/miscellaneous.pngbin1716 -> 1716 bytes
-rw-r--r--files/opencs/modified.pngbin2149 -> 1320 bytes
-rw-r--r--[-rwxr-xr-x]files/opencs/npc.pngbin2143 -> 2143 bytes
-rw-r--r--[-rwxr-xr-x]files/opencs/potion.pngbin1582 -> 1582 bytes
-rw-r--r--[-rwxr-xr-x]files/opencs/probe.pngbin587 -> 587 bytes
-rw-r--r--files/opencs/race.pngbin0 -> 1834 bytes
-rw-r--r--files/opencs/random-item.pngbin0 -> 1698 bytes
-rw-r--r--files/opencs/random.pngbin0 -> 1892 bytes
-rw-r--r--files/opencs/raster/GMST.pngbin0 -> 820 bytes
-rw-r--r--files/opencs/raster/activator.pngbin2297 -> 1913 bytes
-rw-r--r--files/opencs/raster/attribute.pngbin0 -> 1788 bytes
-rw-r--r--files/opencs/raster/body-part.pngbin1788 -> 1248 bytes
-rw-r--r--files/opencs/raster/book.pngbin1336 -> 1599 bytes
-rw-r--r--files/opencs/raster/filter.pngbin0 -> 1375 bytes
-rw-r--r--files/opencs/raster/ingredient.pngbin1444 -> 1384 bytes
-rw-r--r--files/opencs/raster/light.pngbin747 -> 1199 bytes
-rw-r--r--files/opencs/raster/random.pngbin0 -> 1892 bytes
-rw-r--r--files/opencs/raster/soundgen.pngbin2041 -> 2149 bytes
-rw-r--r--files/opencs/raster/startup/big/configure.pngbin0 -> 17972 bytes
-rw-r--r--files/opencs/raster/startup/big/create-addon.pngbin0 -> 37360 bytes
-rw-r--r--files/opencs/raster/startup/big/edit-content.pngbin0 -> 70441 bytes
-rw-r--r--files/opencs/raster/startup/big/new-game.pngbin0 -> 66006 bytes
-rw-r--r--files/opencs/raster/startup/small/configure.pngbin0 -> 1450 bytes
-rw-r--r--files/opencs/raster/startup/small/create-addon.pngbin0 -> 1714 bytes
-rw-r--r--files/opencs/raster/startup/small/edit-content.pngbin0 -> 2471 bytes
-rw-r--r--files/opencs/raster/startup/small/new-game.pngbin0 -> 2122 bytes
-rw-r--r--files/opencs/raster/static.pngbin1518 -> 1297 bytes
-rw-r--r--files/opencs/removed.pngbin1772 -> 1251 bytes
-rw-r--r--[-rwxr-xr-x]files/opencs/repair.pngbin1115 -> 1115 bytes
-rw-r--r--files/opencs/resources.qrc81
-rw-r--r--files/opencs/scalable/referenceable-record/.directory2
-rw-r--r--files/opencs/scalable/referenceable-record/book2.svgzbin0 -> 110316 bytes
-rw-r--r--files/opencs/scalable/referenceable-record/miscellaneous.svg965
-rw-r--r--files/opencs/scalable/startup/configure.svgzbin0 -> 5808 bytes
-rw-r--r--files/opencs/scalable/startup/create-addon.svgzbin0 -> 116154 bytes
-rw-r--r--files/opencs/scalable/startup/edit-content.svgzbin0 -> 120969 bytes
-rw-r--r--files/opencs/scalable/startup/new-game.svgzbin0 -> 113710 bytes
-rw-r--r--files/opencs/script.pngbin0 -> 952 bytes
-rw-r--r--files/opencs/skill.pngbin0 -> 1676 bytes
-rw-r--r--files/opencs/sound.pngbin0 -> 1144 bytes
-rw-r--r--files/opencs/soundgen.pngbin0 -> 2149 bytes
-rw-r--r--files/opencs/spell.pngbin0 -> 2071 bytes
-rw-r--r--[-rwxr-xr-x]files/opencs/static.pngbin1518 -> 1297 bytes
-rw-r--r--[-rwxr-xr-x]files/opencs/weapon.pngbin1003 -> 1003 bytes
-rw-r--r--files/openmw.cfg.local3
-rw-r--r--files/ui/contentselector.ui111
-rw-r--r--files/ui/datafilespage.ui182
-rw-r--r--files/ui/filedialog.ui73
-rw-r--r--libs/openengine/.gitignore3
-rw-r--r--libs/openengine/ogre/.gitignore1
-rw-r--r--libs/openengine/ogre/lights.cpp18
-rw-r--r--libs/openengine/ogre/lights.hpp17
-rw-r--r--readme.txt28
433 files changed, 8108 insertions, 4729 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000000..f22f1bd49c
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,53 @@
+## make
+CMakeFiles
+*/CMakeFiles
+CMakeCache.txt
+cmake_install.cmake
+CMakeLists.txt.user
+Makefile
+makefile
+build
+prebuilt
+
+## doxygen
+Doxygen
+
+## ides/editors
+*~
+*.kdev4
+*.swp
+*.swo
+*.kate-swp
+.cproject
+.project
+.settings
+.directory
+
+## resources
+data
+resources
+/*.cfg
+/*.desktop
+/*.install
+
+## binaries
+/esmtool
+/mwiniimport
+/omwlauncher
+/openmw
+/opencs
+
+## generated objects
+apps/openmw/config.hpp
+Docs/mainpage.hpp
+moc_*.cxx
+*.cxx_parameters
+*qrc_launcher.cxx
+*qrc_resources.cxx
+*__*
+*ui_datafilespage.h
+*ui_graphicspage.h
+*ui_mainwindow.h
+*ui_playpage.h
+*.[ao]
+*.so
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 3f95f2d4e6..01f02ddb96 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -19,7 +19,7 @@ include (OpenMWMacros)
# Version
set (OPENMW_VERSION_MAJOR 0)
-set (OPENMW_VERSION_MINOR 26)
+set (OPENMW_VERSION_MINOR 27)
set (OPENMW_VERSION_RELEASE 0)
set (OPENMW_VERSION "${OPENMW_VERSION_MAJOR}.${OPENMW_VERSION_MINOR}.${OPENMW_VERSION_RELEASE}")
@@ -161,6 +161,20 @@ if (NOT FFMPEG_FOUND)
message(WARNING "--------------------")
endif (NOT FFMPEG_FOUND)
+# TinyXML
+option(USE_SYSTEM_TINYXML "Use system TinyXML library instead of internal." OFF)
+if(USE_SYSTEM_TINYXML)
+ find_library(TINYXML_LIBRARIES tinyxml)
+ find_path(TINYXML_INCLUDE_DIR tinyxml.h)
+ message(STATUS "Found TinyXML: ${TINYXML_LIBRARIES} ${TINYXML_INCLUDE_DIR}")
+ add_definitions (-DTIXML_USE_STL)
+ if(TINYXML_LIBRARIES AND TINYXML_INCLUDE_DIR)
+ include_directories(${TINYXML_INCLUDE_DIR})
+ message(STATUS "Using system TinyXML library.")
+ else()
+ message(FATAL_ERROR "Detection of system TinyXML incomplete.")
+ endif()
+endif()
# Platform specific
if (WIN32)
@@ -305,6 +319,9 @@ configure_file(${OpenMW_SOURCE_DIR}/files/openmw.cfg
configure_file(${OpenMW_SOURCE_DIR}/files/opencs.cfg
"${OpenMW_BINARY_DIR}/opencs.cfg")
+
+configure_file(${OpenMW_SOURCE_DIR}/files/opencs/defaultfilters
+ "${OpenMW_BINARY_DIR}/resources/defaultfilters" COPYONLY)
if (NOT WIN32 AND NOT APPLE)
configure_file(${OpenMW_SOURCE_DIR}/files/openmw.desktop
@@ -366,7 +383,6 @@ IF(NOT WIN32 AND NOT APPLE)
# Install licenses
INSTALL(FILES "DejaVu Font License.txt" DESTINATION "${LICDIR}" )
- INSTALL(FILES "Daedric Font License.txt" DESTINATION "${LICDIR}" )
INSTALL(FILES "OFL.txt" DESTINATION "${LICDIR}" )
INSTALL(FILES "extern/shiny/License.txt" DESTINATION "${LICDIR}" RENAME "Shiny License.txt" )
ENDIF (DPKG_PROGRAM)
@@ -414,7 +430,7 @@ IF(NOT WIN32 AND NOT APPLE)
Data files from the original game is required to run it.")
SET(CPACK_DEBIAN_PACKAGE_NAME "openmw")
SET(CPACK_DEBIAN_PACKAGE_VERSION "${VERSION_STRING}")
- SET(CPACK_PACKAGE_EXECUTABLES "openmw;OpenMW bsatool;Bsatool esmtool;Esmtool omwlauncher;OMWLauncher mwiniimporter;MWiniImporter")
+ SET(CPACK_PACKAGE_EXECUTABLES "openmw;OpenMW opencs;OpenCS bsatool;Bsatool esmtool;Esmtool omwlauncher;OMWLauncher mwiniimporter;MWiniImporter")
SET(CPACK_DEBIAN_PACKAGE_DEPENDS "libc6 (>= 2.11.2), libfreetype6 (>= 2.2.1), libgcc1 (>= 1:4.1.1), libmpg123-0 (>= 1.12.1), libopenal1 (>= 1:1.12.854), libsndfile1 (>= 1.0.23), libstdc++6 (>= 4.4.5), libuuid1 (>= 2.17.2), libqtgui4 (>= 4.7.0)")
SET(CPACK_DEBIAN_PACKAGE_SECTION "Games")
@@ -441,13 +457,22 @@ if(WIN32)
"${OpenMW_SOURCE_DIR}/GPL3.txt"
"${OpenMW_SOURCE_DIR}/OFL.txt"
"${OpenMW_SOURCE_DIR}/DejaVu Font License.txt"
- "${OpenMW_SOURCE_DIR}/Daedric Font License.txt"
"${OpenMW_BINARY_DIR}/settings-default.cfg"
"${OpenMW_BINARY_DIR}/transparency-overrides.cfg"
- "${OpenMW_BINARY_DIR}/Release/mwiniimport.exe"
- "${OpenMW_BINARY_DIR}/Release/omwlauncher.exe"
"${OpenMW_BINARY_DIR}/Release/openmw.exe"
DESTINATION ".")
+
+ IF(BUILD_LAUNCHER)
+ INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/Release/omwlauncher.exe" DESTINATION ".")
+ ENDIF(BUILD_LAUNCHER)
+ IF(BUILD_MWINIIMPORTER)
+ INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/Release/mwiniimport.exe" DESTINATION ".")
+ ENDIF(BUILD_MWINIIMPORTER)
+ IF(BUILD_OPENCS)
+ INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/Release/opencs.exe" DESTINATION ".")
+ INSTALL(FILES "${OpenMW_BINARY_DIR}/opencs.cfg" DESTINATION ".")
+ ENDIF(BUILD_OPENCS)
+
INSTALL(DIRECTORY "${OpenMW_BINARY_DIR}/resources" DESTINATION ".")
SET(CPACK_GENERATOR "NSIS")
@@ -457,7 +482,13 @@ if(WIN32)
SET(CPACK_PACKAGE_VERSION_MAJOR ${OPENMW_VERSION_MAJOR})
SET(CPACK_PACKAGE_VERSION_MINOR ${OPENMW_VERSION_MINOR})
SET(CPACK_PACKAGE_VERSION_PATCH ${OPENMW_VERSION_RELEASE})
- SET(CPACK_PACKAGE_EXECUTABLES "openmw;OpenMW;omwlauncher;OpenMW Launcher")
+ SET(CPACK_PACKAGE_EXECUTABLES "openmw;OpenMW")
+ IF(BUILD_LAUNCHER)
+ SET(CPACK_PACKAGE_EXECUTABLES "${CPACK_PACKAGE_EXECUTABLES};omwlauncher;OpenMW Launcher")
+ ENDIF(BUILD_LAUNCHER)
+ IF(BUILD_OPENCS)
+ SET(CPACK_PACKAGE_EXECUTABLES "${CPACK_PACKAGE_EXECUTABLES};opencs;OpenMW Construction Set")
+ ENDIF(BUILD_OPENCS)
SET(CPACK_NSIS_CREATE_ICONS_EXTRA "CreateShortCut '\$SMPROGRAMS\\\\$STARTMENU_FOLDER\\\\Readme.lnk' '\$INSTDIR\\\\readme.txt'")
SET(CPACK_NSIS_DELETE_ICONS_EXTRA "
!insertmacro MUI_STARTMENU_GETFOLDER Application $MUI_TEMP
@@ -654,7 +685,10 @@ if (APPLE)
set(CPACK_PACKAGE_VERSION_MINOR ${OPENMW_VERSION_MINO})
set(CPACK_PACKAGE_VERSION_PATCH ${OPENMW_VERSION_RELEASE})
- set(APPS "\${CMAKE_INSTALL_PREFIX}/${INSTALL_SUBDIR}/${APP_BUNDLE_NAME}")
+ set(OPENMW_APP "\${CMAKE_INSTALL_PREFIX}/${INSTALL_SUBDIR}/${APP_BUNDLE_NAME}")
+
+ set(OPENCS_APP "\${CMAKE_INSTALL_PREFIX}/${INSTALL_SUBDIR}/OpenCS.app")
+
set(PLUGINS "")
set(ABSOLUTE_PLUGINS "")
@@ -715,7 +749,8 @@ if (APPLE)
cmake_policy(SET CMP0009 OLD)
set(BU_CHMOD_BUNDLE_ITEMS ON)
include(BundleUtilities)
- fixup_bundle(\"${APPS}\" \"${PLUGINS}\" \"${DIRS}\")
+ fixup_bundle(\"${OPENMW_APP}\" \"${PLUGINS}\" \"${DIRS}\")
+ fixup_bundle(\"${OPENCS_APP}\" \"\" \"${DIRS}\")
" COMPONENT Runtime)
include(CPack)
endif (APPLE)
diff --git a/Daedric Font License.txt b/Daedric Font License.txt
deleted file mode 100644
index a1553d0b04..0000000000
--- a/Daedric Font License.txt
+++ /dev/null
@@ -1,10 +0,0 @@
-Dongle's Oblivion Daedric font set
-http://www.uesp.net/wiki/Lore:Daedric_Alphabet#Daedric_Font
-
----------------------------------------------------
-
-This was done entirely as a personal project. Bethesda Softworks graciously granted me the permission for it. I am not connected with them in any way.
-You may freely use these fonts to create anything you'd like. You may re-distribute the fonts freely, over the Internet, or by any other means. Always keep the .zip file intact, and this read me included.
-Please do not modify and redistribute the fonts without my permission.
-You may NOT sell any of these fonts under any circumstances. This includes putting them on compilation font CDs for sale, putting them in a "members only" pay-area of a website, or any other means of financial gain connected in ANY way with the redistribution of any of these fonts.
-You have my permission to create and sell any artwork made with these fonts, however you may need to contact Bethesda Softworks before doing so.
diff --git a/apps/esmtool/.gitignore b/apps/esmtool/.gitignore
new file mode 100644
index 0000000000..d20f8fd880
--- /dev/null
+++ b/apps/esmtool/.gitignore
@@ -0,0 +1,6 @@
+*.esp
+*.esm
+*.ess
+*_test
+esmtool
+*_raw.txt
diff --git a/apps/esmtool/esmtool.cpp b/apps/esmtool/esmtool.cpp
index a60e9f0e20..6ccf9c3f3b 100644
--- a/apps/esmtool/esmtool.cpp
+++ b/apps/esmtool/esmtool.cpp
@@ -305,14 +305,14 @@ int load(Arguments& info)
info.data.author = esm.getAuthor();
info.data.description = esm.getDesc();
- info.data.masters = esm.getMasters();
+ info.data.masters = esm.getGameFiles();
if (!quiet)
{
std::cout << "Author: " << esm.getAuthor() << std::endl
<< "Description: " << esm.getDesc() << std::endl
<< "File format version: " << esm.getFVer() << std::endl;
- std::vector<ESM::Header::MasterData> m = esm.getMasters();
+ std::vector<ESM::Header::MasterData> m = esm.getGameFiles();
if (!m.empty())
{
std::cout << "Masters:" << std::endl;
diff --git a/apps/launcher/CMakeLists.txt b/apps/launcher/CMakeLists.txt
index 5908deb907..18c555a249 100644
--- a/apps/launcher/CMakeLists.txt
+++ b/apps/launcher/CMakeLists.txt
@@ -11,7 +11,9 @@ set(LAUNCHER
settings/launchersettings.cpp
utils/checkablemessagebox.cpp
+ utils/profilescombobox.cpp
utils/textinputdialog.cpp
+ utils/lineedit.cpp
${CMAKE_SOURCE_DIR}/files/launcher/launcher.rc
)
@@ -24,7 +26,6 @@ set(LAUNCHER_HEADER
graphicspage.hpp
maindialog.hpp
playpage.hpp
- unshieldthread.hpp
textslotmsgbox.hpp
settings/gamesettings.hpp
@@ -33,8 +34,9 @@ set(LAUNCHER_HEADER
settings/settingsbase.hpp
utils/checkablemessagebox.hpp
+ utils/profilescombobox.hpp
utils/textinputdialog.hpp
-
+ utils/lineedit.hpp
)
if(NOT WIN32)
LIST(APPEND LAUNCHER_HEADER unshieldthread.hpp)
@@ -47,11 +49,13 @@ set(LAUNCHER_HEADER_MOC
graphicspage.hpp
maindialog.hpp
playpage.hpp
- unshieldthread.hpp
textslotmsgbox.hpp
- utils/checkablemessagebox.hpp
utils/textinputdialog.hpp
+ utils/checkablemessagebox.hpp
+ utils/profilescombobox.hpp
+ utils/lineedit.hpp
+
)
if(NOT WIN32)
@@ -64,6 +68,7 @@ set(LAUNCHER_UI
${CMAKE_SOURCE_DIR}/files/ui/graphicspage.ui
${CMAKE_SOURCE_DIR}/files/ui/mainwindow.ui
${CMAKE_SOURCE_DIR}/files/ui/playpage.ui
+ ${CMAKE_SOURCE_DIR}/files/ui/contentselector.ui
)
source_group(launcher FILES ${LAUNCHER} ${LAUNCHER_HEADER})
diff --git a/apps/launcher/datafilespage.cpp b/apps/launcher/datafilespage.cpp
index add3dea40e..734277b97d 100644
--- a/apps/launcher/datafilespage.cpp
+++ b/apps/launcher/datafilespage.cpp
@@ -4,548 +4,307 @@
#include <QMessageBox>
#include <QCheckBox>
#include <QMenu>
+#include <QSortFilterProxyModel>
#include <components/files/configurationmanager.hpp>
-#include <components/fileorderlist/model/datafilesmodel.hpp>
-#include <components/fileorderlist/model/pluginsproxymodel.hpp>
-#include <components/fileorderlist/model/esm/esmfile.hpp>
+#include <components/contentselector/model/esmfile.hpp>
-#include <components/fileorderlist/utils/lineedit.hpp>
-#include <components/fileorderlist/utils/naturalsort.hpp>
-#include <components/fileorderlist/utils/profilescombobox.hpp>
+#include <components/contentselector/model/naturalsort.hpp>
+
+#include "utils/textinputdialog.hpp"
+#include "utils/profilescombobox.hpp"
#include "settings/gamesettings.hpp"
#include "settings/launchersettings.hpp"
-#include "utils/textinputdialog.hpp"
+#include "components/contentselector/view/contentselector.hpp"
-DataFilesPage::DataFilesPage(Files::ConfigurationManager &cfg, GameSettings &gameSettings, LauncherSettings &launcherSettings, QWidget *parent)
+Launcher::DataFilesPage::DataFilesPage(Files::ConfigurationManager &cfg, GameSettings &gameSettings, LauncherSettings &launcherSettings, QWidget *parent)
: mCfgMgr(cfg)
, mGameSettings(gameSettings)
, mLauncherSettings(launcherSettings)
, QWidget(parent)
{
- setupUi(this);
-
- // Models
- mDataFilesModel = new DataFilesModel(this);
-
- mMastersProxyModel = new QSortFilterProxyModel();
- mMastersProxyModel->setFilterRegExp(QString("^.*\\.esm"));
- mMastersProxyModel->setFilterCaseSensitivity(Qt::CaseInsensitive);
- mMastersProxyModel->setSourceModel(mDataFilesModel);
-
- mPluginsProxyModel = new PluginsProxyModel();
- mPluginsProxyModel->setFilterRegExp(QString("^.*\\.esp"));
- mPluginsProxyModel->setFilterCaseSensitivity(Qt::CaseInsensitive);
- mPluginsProxyModel->setSourceModel(mDataFilesModel);
-
- mFilterProxyModel = new QSortFilterProxyModel();
- mFilterProxyModel->setDynamicSortFilter(true);
- mFilterProxyModel->setSourceModel(mPluginsProxyModel);
-
- QCheckBox checkBox;
- unsigned int height = checkBox.sizeHint().height() + 4;
-
- mastersTable->setModel(mMastersProxyModel);
- mastersTable->setObjectName("MastersTable");
- mastersTable->setContextMenuPolicy(Qt::CustomContextMenu);
- mastersTable->setSortingEnabled(false);
- mastersTable->setSelectionBehavior(QAbstractItemView::SelectRows);
- mastersTable->setSelectionMode(QAbstractItemView::ExtendedSelection);
- mastersTable->setEditTriggers(QAbstractItemView::NoEditTriggers);
- mastersTable->setAlternatingRowColors(true);
- mastersTable->horizontalHeader()->setStretchLastSection(true);
- mastersTable->horizontalHeader()->hide();
-
- // Set the row height to the size of the checkboxes
- mastersTable->verticalHeader()->setDefaultSectionSize(height);
- mastersTable->verticalHeader()->setResizeMode(QHeaderView::Fixed);
- mastersTable->verticalHeader()->hide();
-
- pluginsTable->setModel(mFilterProxyModel);
- pluginsTable->setObjectName("PluginsTable");
- pluginsTable->setContextMenuPolicy(Qt::CustomContextMenu);
- pluginsTable->setSortingEnabled(false);
- pluginsTable->setSelectionBehavior(QAbstractItemView::SelectRows);
- pluginsTable->setSelectionMode(QAbstractItemView::ExtendedSelection);
- pluginsTable->setEditTriggers(QAbstractItemView::NoEditTriggers);
- pluginsTable->setAlternatingRowColors(true);
- pluginsTable->setVerticalScrollMode(QAbstractItemView::ScrollPerItem);
- pluginsTable->horizontalHeader()->setStretchLastSection(true);
- pluginsTable->horizontalHeader()->hide();
-
- pluginsTable->verticalHeader()->setDefaultSectionSize(height);
- pluginsTable->verticalHeader()->setResizeMode(QHeaderView::Fixed);
-
- // Adjust the tableview widths inside the splitter
- QList<int> sizeList;
- sizeList << mLauncherSettings.value(QString("General/MastersTable/width"), QString("200")).toInt();
- sizeList << mLauncherSettings.value(QString("General/PluginTable/width"), QString("340")).toInt();
-
- splitter->setSizes(sizeList);
-
- // Create a dialog for the new profile name input
- mNewProfileDialog = new TextInputDialog(tr("New Profile"), tr("Profile name:"), this);
-
- connect(profilesComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(slotCurrentIndexChanged(int)));
-
- connect(mNewProfileDialog->lineEdit(), SIGNAL(textChanged(QString)), this, SLOT(updateOkButton(QString)));
-
- connect(pluginsTable, SIGNAL(doubleClicked(QModelIndex)), this, SLOT(setCheckState(QModelIndex)));
- connect(mastersTable, SIGNAL(doubleClicked(QModelIndex)), this, SLOT(setCheckState(QModelIndex)));
-
- connect(pluginsTable, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(showContextMenu(QPoint)));
- connect(mastersTable, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(showContextMenu(QPoint)));
-
- connect(mDataFilesModel, SIGNAL(layoutChanged()), this, SLOT(updateViews()));
-
- connect(filterLineEdit, SIGNAL(textChanged(QString)), this, SLOT(filterChanged(QString)));
+ ui.setupUi (this);
+ setObjectName ("DataFilesPage");
+ mSelector = new ContentSelectorView::ContentSelector (ui.contentSelectorWidget);
- connect(splitter, SIGNAL(splitterMoved(int,int)), this, SLOT(updateSplitter()));
-
- createActions();
+ buildView();
setupDataFiles();
}
-void DataFilesPage::createActions()
-{
-
- // Add the actions to the toolbuttons
- newProfileButton->setDefaultAction(newProfileAction);
- deleteProfileButton->setDefaultAction(deleteProfileAction);
-
- // Context menu actions
- mContextMenu = new QMenu(this);
- mContextMenu->addAction(checkAction);
- mContextMenu->addAction(uncheckAction);
-}
-
-void DataFilesPage::setupDataFiles()
+void Launcher::DataFilesPage::loadSettings()
{
- // Set the encoding to the one found in openmw.cfg or the default
- mDataFilesModel->setEncoding(mGameSettings.value(QString("encoding"), QString("win1252")));
-
QStringList paths = mGameSettings.getDataDirs();
+ paths.insert (0, mDataLocal);
+ PathIterator pathIterator (paths);
- foreach (const QString &path, paths) {
- mDataFilesModel->addFiles(path);
- }
-
- QString dataLocal = mGameSettings.getDataLocal();
- if (!dataLocal.isEmpty())
- mDataFilesModel->addFiles(dataLocal);
+ QString profileName = ui.profilesComboBox->currentText();
- // Sort by date accessed for now
- mDataFilesModel->sort(3);
+ QStringList files = mLauncherSettings.values(QString("Profiles/") + profileName, Qt::MatchExactly);
- QStringList profiles = mLauncherSettings.subKeys(QString("Profiles/"));
- QString profile = mLauncherSettings.value(QString("Profiles/currentprofile"));
-
- if (!profiles.isEmpty())
- profilesComboBox->addItems(profiles);
-
- // Add the current profile if empty
- if (profilesComboBox->findText(profile) == -1 && !profile.isEmpty())
- profilesComboBox->addItem(profile);
-
- if (profilesComboBox->findText(QString("Default")) == -1)
- profilesComboBox->addItem(QString("Default"));
-
- if (profile.isEmpty() || profile == QLatin1String("Default")) {
- deleteProfileAction->setEnabled(false);
- profilesComboBox->setEditEnabled(false);
- profilesComboBox->setCurrentIndex(profilesComboBox->findText(QString("Default")));
- } else {
- profilesComboBox->setEditEnabled(true);
- profilesComboBox->setCurrentIndex(profilesComboBox->findText(profile));
- }
-
- // We do this here to prevent deletion of profiles when initializing the combobox
- connect(profilesComboBox, SIGNAL(profileRenamed(QString,QString)), this, SLOT(profileRenamed(QString,QString)));
- connect(profilesComboBox, SIGNAL(profileChanged(QString,QString)), this, SLOT(profileChanged(QString,QString)));
-
- loadSettings();
-
-}
+ QStringList filepaths;
-void DataFilesPage::loadSettings()
-{
- QString profile = mLauncherSettings.value(QString("Profiles/currentprofile"));
-
- if (profile.isEmpty())
- return;
-
- mDataFilesModel->uncheckAll();
-
- QStringList masters = mLauncherSettings.values(QString("Profiles/") + profile + QString("/master"), Qt::MatchExactly);
- QStringList plugins = mLauncherSettings.values(QString("Profiles/") + profile + QString("/plugin"), Qt::MatchExactly);
+ foreach (const QString &file, files)
+ {
+ QString filepath = pathIterator.findFirstPath (file);
- foreach (const QString &master, masters) {
- QModelIndex index = mDataFilesModel->indexFromItem(mDataFilesModel->findItem(master));
- if (index.isValid())
- mDataFilesModel->setCheckState(index, Qt::Checked);
+ if (!filepath.isEmpty())
+ filepaths << filepath;
}
- foreach (const QString &plugin, plugins) {
- QModelIndex index = mDataFilesModel->indexFromItem(mDataFilesModel->findItem(plugin));
- if (index.isValid())
- mDataFilesModel->setCheckState(index, Qt::Checked);
- }
+ mSelector->setProfileContent (filepaths);
}
-void DataFilesPage::saveSettings()
+void Launcher::DataFilesPage::saveSettings(const QString &profile)
{
- if (mDataFilesModel->rowCount() < 1)
- return;
-
- QString profile = mLauncherSettings.value(QString("Profiles/currentprofile"));
+ QString profileName = profile;
- if (profile.isEmpty()) {
- profile = profilesComboBox->currentText();
- mLauncherSettings.setValue(QString("Profiles/currentprofile"), profile);
- }
+ if (profileName.isEmpty())
+ profileName = ui.profilesComboBox->currentText();
- mLauncherSettings.remove(QString("Profiles/") + profile + QString("/master"));
- mLauncherSettings.remove(QString("Profiles/") + profile + QString("/plugin"));
+ //retrieve the files selected for the profile
+ ContentSelectorModel::ContentFileList items = mSelector->selectedFiles();
- mGameSettings.remove(QString("master"));
- mGameSettings.remove(QString("plugin"));
+ removeProfile (profileName);
- QStringList items = mDataFilesModel->checkedItems();
+ mGameSettings.remove(QString("content"));
- foreach(const QString &item, items) {
+ //set the value of the current profile (not necessarily the profile being saved!)
+ mLauncherSettings.setValue(QString("Profiles/currentprofile"), ui.profilesComboBox->currentText());
- if (item.endsWith(QString(".esm"), Qt::CaseInsensitive)) {
- mLauncherSettings.setMultiValue(QString("Profiles/") + profile + QString("/master"), item);
- mGameSettings.setMultiValue(QString("master"), item);
+ foreach(const ContentSelectorModel::EsmFile *item, items) {
- } else if (item.endsWith(QString(".esp"), Qt::CaseInsensitive)) {
- mLauncherSettings.setMultiValue(QString("Profiles/") + profile + QString("/plugin"), item);
- mGameSettings.setMultiValue(QString("plugin"), item);
+ if (item->gameFiles().size() == 0) {
+ mLauncherSettings.setMultiValue(QString("Profiles/") + profileName, item->fileName());
+ mGameSettings.setMultiValue(QString("content"), item->fileName());
+ } else {
+ mLauncherSettings.setMultiValue(QString("Profiles/") + profileName, item->fileName());
+ mGameSettings.setMultiValue(QString("content"), item->fileName());
}
}
}
-void DataFilesPage::updateOkButton(const QString &text)
+void Launcher::DataFilesPage::buildView()
{
- // We do this here because we need the profiles combobox text
- if (text.isEmpty()) {
- mNewProfileDialog->setOkButtonEnabled(false);
- return;
- }
+ ui.verticalLayout->insertWidget (0, mSelector->uiWidget());
- (profilesComboBox->findText(text) == -1)
- ? mNewProfileDialog->setOkButtonEnabled(true)
- : mNewProfileDialog->setOkButtonEnabled(false);
-}
+ //tool buttons
+ ui.newProfileButton->setToolTip ("Create a new profile");
+ ui.deleteProfileButton->setToolTip ("Delete an existing profile");
-void DataFilesPage::updateSplitter()
-{
- // Sigh, update the saved splitter size in settings only when moved
- // Since getting mSplitter->sizes() if page is hidden returns invalid values
- QList<int> sizes = splitter->sizes();
+ //combo box
+ ui.profilesComboBox->addItem ("Default");
+ ui.profilesComboBox->setPlaceholderText (QString("Select a profile..."));
- mLauncherSettings.setValue(QString("General/MastersTable/width"), QString::number(sizes.at(0)));
- mLauncherSettings.setValue(QString("General/PluginsTable/width"), QString::number(sizes.at(1)));
-}
+ // Add the actions to the toolbuttons
+ ui.newProfileButton->setDefaultAction (ui.newProfileAction);
+ ui.deleteProfileButton->setDefaultAction (ui.deleteProfileAction);
-void DataFilesPage::updateViews()
-{
- // Ensure the columns are hidden because sort() re-enables them
- mastersTable->setColumnHidden(1, true);
- mastersTable->setColumnHidden(2, true);
- mastersTable->setColumnHidden(3, true);
- mastersTable->setColumnHidden(4, true);
- mastersTable->setColumnHidden(5, true);
- mastersTable->setColumnHidden(6, true);
- mastersTable->setColumnHidden(7, true);
- mastersTable->setColumnHidden(8, true);
-
- pluginsTable->setColumnHidden(1, true);
- pluginsTable->setColumnHidden(2, true);
- pluginsTable->setColumnHidden(3, true);
- pluginsTable->setColumnHidden(4, true);
- pluginsTable->setColumnHidden(5, true);
- pluginsTable->setColumnHidden(6, true);
- pluginsTable->setColumnHidden(7, true);
- pluginsTable->setColumnHidden(8, true);
-}
+ //establish connections
+ connect (ui.profilesComboBox, SIGNAL (currentIndexChanged(int)),
+ this, SLOT (slotProfileChanged(int)));
-void DataFilesPage::setProfilesComboBoxIndex(int index)
-{
- profilesComboBox->setCurrentIndex(index);
+ connect (ui.profilesComboBox, SIGNAL (profileRenamed(QString, QString)),
+ this, SLOT (slotProfileRenamed(QString, QString)));
+
+ connect (ui.profilesComboBox, SIGNAL (signalProfileChanged(QString, QString)),
+ this, SLOT (slotProfileChangedByUser(QString, QString)));
}
-void DataFilesPage::slotCurrentIndexChanged(int index)
+void Launcher::DataFilesPage::removeProfile(const QString &profile)
{
- emit profileChanged(index);
+ mLauncherSettings.remove(QString("Profiles/") + profile + QString("/game"));
+ mLauncherSettings.remove(QString("Profiles/") + profile + QString("/addon"));
}
-QAbstractItemModel* DataFilesPage::profilesComboBoxModel()
+QAbstractItemModel *Launcher::DataFilesPage::profilesModel() const
{
- return profilesComboBox->model();
+ return ui.profilesComboBox->model();
}
-int DataFilesPage::profilesComboBoxIndex()
+int Launcher::DataFilesPage::profilesIndex() const
{
- return profilesComboBox->currentIndex();
+ return ui.profilesComboBox->currentIndex();
}
-void DataFilesPage::on_newProfileAction_triggered()
+void Launcher::DataFilesPage::setProfile(int index, bool savePrevious)
{
- if (mNewProfileDialog->exec() == QDialog::Accepted) {
- QString profile = mNewProfileDialog->lineEdit()->text();
- profilesComboBox->addItem(profile);
- profilesComboBox->setCurrentIndex(profilesComboBox->findText(profile));
+ if (index >= -1 && index < ui.profilesComboBox->count())
+ {
+ QString previous = ui.profilesComboBox->itemText(ui.profilesComboBox->currentIndex());
+ QString current = ui.profilesComboBox->itemText(index);
+
+ setProfile (previous, current, savePrevious);
}
}
-void DataFilesPage::on_deleteProfileAction_triggered()
+void Launcher::DataFilesPage::setProfile (const QString &previous, const QString &current, bool savePrevious)
{
- QString profile = profilesComboBox->currentText();
-
- if (profile.isEmpty())
- return;
-
- QMessageBox msgBox(this);
- msgBox.setWindowTitle(tr("Delete Profile"));
- msgBox.setIcon(QMessageBox::Warning);
- msgBox.setStandardButtons(QMessageBox::Cancel);
- msgBox.setText(tr("Are you sure you want to delete <b>%0</b>?").arg(profile));
+ //abort if no change (poss. duplicate signal)
+ if (previous == current)
+ return;
- QAbstractButton *deleteButton =
- msgBox.addButton(tr("Delete"), QMessageBox::ActionRole);
+ if (!previous.isEmpty() && savePrevious)
+ saveSettings (previous);
- msgBox.exec();
+ ui.profilesComboBox->setCurrentProfile (ui.profilesComboBox->findText (current));
- if (msgBox.clickedButton() == deleteButton) {
- mLauncherSettings.remove(QString("Profiles/") + profile + QString("/master"));
- mLauncherSettings.remove(QString("Profiles/") + profile + QString("/plugin"));
+ loadSettings();
- // Remove the profile from the combobox
- profilesComboBox->removeItem(profilesComboBox->findText(profile));
- }
+ checkForDefaultProfile();
}
-void DataFilesPage::on_checkAction_triggered()
+void Launcher::DataFilesPage::slotProfileDeleted (const QString &item)
{
- if (pluginsTable->hasFocus())
- setPluginsCheckstates(Qt::Checked);
-
- if (mastersTable->hasFocus())
- setMastersCheckstates(Qt::Checked);
-
+ removeProfile (item);
}
-void DataFilesPage::on_uncheckAction_triggered()
+void Launcher::DataFilesPage::slotProfileChangedByUser(const QString &previous, const QString &current)
{
- if (pluginsTable->hasFocus())
- setPluginsCheckstates(Qt::Unchecked);
-
- if (mastersTable->hasFocus())
- setMastersCheckstates(Qt::Unchecked);
+ setProfile(previous, current, true);
+ emit signalProfileChanged (ui.profilesComboBox->findText(current));
}
-void DataFilesPage::setMastersCheckstates(Qt::CheckState state)
+void Launcher::DataFilesPage::slotProfileRenamed(const QString &previous, const QString &current)
{
- if (!mastersTable->selectionModel()->hasSelection()) {
+ if (previous.isEmpty())
return;
- }
-
- QModelIndexList indexes = mastersTable->selectionModel()->selectedIndexes();
-
- foreach (const QModelIndex &index, indexes)
- {
- if (!index.isValid())
- return;
- QModelIndex sourceIndex = mMastersProxyModel->mapToSource(index);
+ // Save the new profile name
+ saveSettings();
- if (!sourceIndex.isValid())
- return;
+ // Remove the old one
+ removeProfile (previous);
- mDataFilesModel->setCheckState(sourceIndex, state);
- }
+ loadSettings();
}
-void DataFilesPage::setPluginsCheckstates(Qt::CheckState state)
+void Launcher::DataFilesPage::slotProfileChanged(int index)
{
- if (!pluginsTable->selectionModel()->hasSelection()) {
- return;
- }
-
- QModelIndexList indexes = pluginsTable->selectionModel()->selectedIndexes();
-
- foreach (const QModelIndex &index, indexes)
- {
- if (!index.isValid())
- return;
-
- QModelIndex sourceIndex = mPluginsProxyModel->mapToSource(
- mFilterProxyModel->mapToSource(index));
-
- if (!sourceIndex.isValid())
- return;
-
- mDataFilesModel->setCheckState(sourceIndex, state);
- }
+ setProfile (index, true);
}
-void DataFilesPage::setCheckState(QModelIndex index)
+void Launcher::DataFilesPage::setupDataFiles()
{
- if (!index.isValid())
- return;
+ QStringList paths = mGameSettings.getDataDirs();
- QObject *object = QObject::sender();
+ foreach (const QString &path, paths)
+ mSelector->addFiles(path);
- // Not a signal-slot call
- if (!object)
- return;
+ mDataLocal = mGameSettings.getDataLocal();
+ if (!mDataLocal.isEmpty())
+ mSelector->addFiles(mDataLocal);
- if (object->objectName() == QLatin1String("PluginsTable")) {
- QModelIndex sourceIndex = mPluginsProxyModel->mapToSource(
- mFilterProxyModel->mapToSource(index));
+ QStringList profiles;
+ QString currentProfile = mLauncherSettings.getSettings().value("Profiles/currentprofile");
- if (sourceIndex.isValid()) {
- (mDataFilesModel->checkState(sourceIndex) == Qt::Checked)
- ? mDataFilesModel->setCheckState(sourceIndex, Qt::Unchecked)
- : mDataFilesModel->setCheckState(sourceIndex, Qt::Checked);
+ foreach (QString key, mLauncherSettings.getSettings().keys())
+ {
+ if (key.contains("Profiles/"))
+ {
+ QString profile = key.mid (9);
+ if (profile != "currentprofile")
+ {
+ if (!profiles.contains(profile))
+ profiles << profile;
+ }
}
}
- if (object->objectName() == QLatin1String("MastersTable")) {
- QModelIndex sourceIndex = mMastersProxyModel->mapToSource(index);
-
- if (sourceIndex.isValid()) {
- (mDataFilesModel->checkState(sourceIndex) == Qt::Checked)
- ? mDataFilesModel->setCheckState(sourceIndex, Qt::Unchecked)
- : mDataFilesModel->setCheckState(sourceIndex, Qt::Checked);
- }
- }
+ foreach (const QString &item, profiles)
+ addProfile (item, false);
- return;
-}
+ setProfile (ui.profilesComboBox->findText(currentProfile), false);
-void DataFilesPage::filterChanged(const QString filter)
-{
- QRegExp regExp(filter, Qt::CaseInsensitive, QRegExp::FixedString);
- mFilterProxyModel->setFilterRegExp(regExp);
+ loadSettings();
}
-void DataFilesPage::profileChanged(const QString &previous, const QString &current)
+void Launcher::DataFilesPage::on_newProfileAction_triggered()
{
- // Prevent the deletion of the default profile
- if (current == QLatin1String("Default")) {
- deleteProfileAction->setEnabled(false);
- profilesComboBox->setEditEnabled(false);
- } else {
- deleteProfileAction->setEnabled(true);
- profilesComboBox->setEditEnabled(true);
- }
+ TextInputDialog newDialog (tr("New Profile"), tr("Profile name:"), this);
- if (previous.isEmpty())
+ if (newDialog.exec() != QDialog::Accepted)
return;
- if (profilesComboBox->findText(previous) == -1)
- return; // Profile was deleted
-
- // Store the previous profile
- mLauncherSettings.setValue(QString("Profiles/currentprofile"), previous);
- saveSettings();
- mLauncherSettings.setValue(QString("Profiles/currentprofile"), current);
-
- loadSettings();
-}
+ QString profile = newDialog.getText();
-void DataFilesPage::profileRenamed(const QString &previous, const QString &current)
-{
- if (previous.isEmpty())
- return;
+ if (profile.isEmpty())
+ return;
- // Save the new profile name
- mLauncherSettings.setValue(QString("Profiles/currentprofile"), current);
saveSettings();
- // Remove the old one
- mLauncherSettings.remove(QString("Profiles/") + previous + QString("/master"));
- mLauncherSettings.remove(QString("Profiles/") + previous + QString("/plugin"));
+ mSelector->clearCheckStates();
- // Remove the profile from the combobox
- profilesComboBox->removeItem(profilesComboBox->findText(previous));
+ addProfile(profile, true);
- loadSettings();
+ mSelector->setGameFile();
+
+ saveSettings();
+ emit signalProfileChanged (ui.profilesComboBox->findText(profile));
}
-void DataFilesPage::showContextMenu(const QPoint &point)
+void Launcher::DataFilesPage::addProfile (const QString &profile, bool setAsCurrent)
{
- QObject *object = QObject::sender();
+ if (profile.isEmpty())
+ return;
- // Not a signal-slot call
- if (!object)
+ if (ui.profilesComboBox->findText (profile) != -1)
return;
- if (object->objectName() == QLatin1String("PluginsTable")) {
- if (!pluginsTable->selectionModel()->hasSelection())
- return;
+ ui.profilesComboBox->addItem (profile);
- QPoint globalPos = pluginsTable->mapToGlobal(point);
- QModelIndexList indexes = pluginsTable->selectionModel()->selectedIndexes();
+ if (setAsCurrent)
+ setProfile (ui.profilesComboBox->findText (profile), false);
+}
- // Show the check/uncheck actions depending on the state of the selected items
- uncheckAction->setEnabled(false);
- checkAction->setEnabled(false);
+void Launcher::DataFilesPage::on_deleteProfileAction_triggered()
+{
+ QString profile = ui.profilesComboBox->currentText();
- foreach (const QModelIndex &index, indexes)
- {
- if (!index.isValid())
- return;
+ if (profile.isEmpty())
+ return;
- QModelIndex sourceIndex = mPluginsProxyModel->mapToSource(
- mFilterProxyModel->mapToSource(index));
+ if (!showDeleteMessageBox (profile))
+ return;
- if (!sourceIndex.isValid())
- return;
+ // Remove the profile from the combobox
+ ui.profilesComboBox->removeItem (ui.profilesComboBox->findText (profile));
- (mDataFilesModel->checkState(sourceIndex) == Qt::Checked)
- ? uncheckAction->setEnabled(true)
- : checkAction->setEnabled(true);
- }
+ removeProfile(profile);
- // Show menu
- mContextMenu->exec(globalPos);
- }
+ saveSettings();
- if (object->objectName() == QLatin1String("MastersTable")) {
- if (!mastersTable->selectionModel()->hasSelection())
- return;
+ loadSettings();
- QPoint globalPos = mastersTable->mapToGlobal(point);
- QModelIndexList indexes = mastersTable->selectionModel()->selectedIndexes();
+ checkForDefaultProfile();
+}
- // Show the check/uncheck actions depending on the state of the selected items
- uncheckAction->setEnabled(false);
- checkAction->setEnabled(false);
+void Launcher::DataFilesPage::checkForDefaultProfile()
+{
+ //don't allow deleting "Default" profile
+ bool success = (ui.profilesComboBox->currentText() != "Default");
- foreach (const QModelIndex &index, indexes)
- {
- if (!index.isValid())
- return;
+ ui.deleteProfileAction->setEnabled (success);
+ ui.profilesComboBox->setEditEnabled (success);
+}
- QModelIndex sourceIndex = mMastersProxyModel->mapToSource(index);
+bool Launcher::DataFilesPage::showDeleteMessageBox (const QString &text)
+{
+ QMessageBox msgBox(this);
+ msgBox.setWindowTitle(tr("Delete Profile"));
+ msgBox.setIcon(QMessageBox::Warning);
+ msgBox.setStandardButtons(QMessageBox::Cancel);
+ msgBox.setText(tr("Are you sure you want to delete <b>%0</b>?").arg(text));
- if (!sourceIndex.isValid())
- return;
+ QAbstractButton *deleteButton =
+ msgBox.addButton(tr("Delete"), QMessageBox::ActionRole);
- (mDataFilesModel->checkState(sourceIndex) == Qt::Checked)
- ? uncheckAction->setEnabled(true)
- : checkAction->setEnabled(true);
- }
+ msgBox.exec();
- mContextMenu->exec(globalPos);
- }
+ return (msgBox.clickedButton() == deleteButton);
}
diff --git a/apps/launcher/datafilespage.hpp b/apps/launcher/datafilespage.hpp
index a0b0293309..37603a2106 100644
--- a/apps/launcher/datafilespage.hpp
+++ b/apps/launcher/datafilespage.hpp
@@ -1,88 +1,136 @@
#ifndef DATAFILESPAGE_H
#define DATAFILESPAGE_H
+#include "ui_datafilespage.h"
#include <QWidget>
-#include <QModelIndex>
-#include "ui_datafilespage.h"
+
+#include <QDir>
+#include <QFile>
class QSortFilterProxyModel;
class QAbstractItemModel;
-class QAction;
class QMenu;
-class DataFilesModel;
-class TextInputDialog;
-class GameSettings;
-class LauncherSettings;
-class PluginsProxyModel;
-
namespace Files { struct ConfigurationManager; }
+namespace ContentSelectorView { class ContentSelector; }
-class DataFilesPage : public QWidget, private Ui::DataFilesPage
+namespace Launcher
{
- Q_OBJECT
+ class TextInputDialog;
+ class GameSettings;
+ class LauncherSettings;
+ class ProfilesComboBox;
+
+ class DataFilesPage : public QWidget
+ {
+ Q_OBJECT
+
+ ContentSelectorView::ContentSelector *mSelector;
+ Ui::DataFilesPage ui;
+
+ public:
+ explicit DataFilesPage (Files::ConfigurationManager &cfg, GameSettings &gameSettings,
+ LauncherSettings &launcherSettings, QWidget *parent = 0);
+
+ QAbstractItemModel* profilesModel() const;
+
+ int profilesIndex() const;
+
+ //void writeConfig(QString profile = QString());
+ void saveSettings(const QString &profile = "");
+ void loadSettings();
+
+ signals:
+ void signalProfileChanged (int index);
+
+ public slots:
+ void slotProfileChanged (int index);
+
+ private slots:
+
+ void slotProfileChangedByUser(const QString &previous, const QString &current);
+ void slotProfileRenamed(const QString &previous, const QString &current);
+ void slotProfileDeleted(const QString &item);
-public:
- DataFilesPage(Files::ConfigurationManager &cfg, GameSettings &gameSettings, LauncherSettings &launcherSettings, QWidget *parent = 0);
+ void on_newProfileAction_triggered();
+ void on_deleteProfileAction_triggered();
- QAbstractItemModel* profilesComboBoxModel();
- int profilesComboBoxIndex();
+ private:
- void writeConfig(QString profile = QString());
- void saveSettings();
+ QMenu *mContextMenu;
-signals:
- void profileChanged(int index);
+ Files::ConfigurationManager &mCfgMgr;
-public slots:
- void setCheckState(QModelIndex index);
- void setProfilesComboBoxIndex(int index);
+ GameSettings &mGameSettings;
+ LauncherSettings &mLauncherSettings;
- void filterChanged(const QString filter);
- void showContextMenu(const QPoint &point);
- void profileChanged(const QString &previous, const QString &current);
- void profileRenamed(const QString &previous, const QString &current);
- void updateOkButton(const QString &text);
- void updateSplitter();
- void updateViews();
+ QString mDataLocal;
- // Action slots
- void on_newProfileAction_triggered();
- void on_deleteProfileAction_triggered();
- void on_checkAction_triggered();
- void on_uncheckAction_triggered();
+ void setPluginsCheckstates(Qt::CheckState state);
-private slots:
- void slotCurrentIndexChanged(int index);
+ void buildView();
+ void setupDataFiles();
+ void setupConfig();
+ void readConfig();
+ void setProfile (int index, bool savePrevious);
+ void setProfile (const QString &previous, const QString &current, bool savePrevious);
+ void removeProfile (const QString &profile);
+ bool showDeleteMessageBox (const QString &text);
+ void addProfile (const QString &profile, bool setAsCurrent);
+ void checkForDefaultProfile();
-private:
- DataFilesModel *mDataFilesModel;
+ class PathIterator
+ {
+ QStringList::ConstIterator mCitEnd;
+ QStringList::ConstIterator mCitCurrent;
+ QStringList::ConstIterator mCitBegin;
+ QString mFile;
+ QString mFilePath;
- PluginsProxyModel *mPluginsProxyModel;
- QSortFilterProxyModel *mMastersProxyModel;
+ public:
+ PathIterator (const QStringList &list)
+ {
+ mCitBegin = list.constBegin();
+ mCitCurrent = mCitBegin;
+ mCitEnd = list.constEnd();
+ }
- QSortFilterProxyModel *mFilterProxyModel;
+ QString findFirstPath (const QString &file)
+ {
+ mCitCurrent = mCitBegin;
+ mFile = file;
+ return path();
+ }
- QMenu *mContextMenu;
+ QString findNextPath () { return path(); }
- Files::ConfigurationManager &mCfgMgr;
+ private:
- GameSettings &mGameSettings;
- LauncherSettings &mLauncherSettings;
+ QString path ()
+ {
+ bool success = false;
+ QDir dir;
+ QFileInfo file;
- TextInputDialog *mNewProfileDialog;
+ while (!success)
+ {
+ if (mCitCurrent == mCitEnd)
+ break;
- void setMastersCheckstates(Qt::CheckState state);
- void setPluginsCheckstates(Qt::CheckState state);
+ dir.setPath (*(mCitCurrent++));
+ file.setFile (dir.absoluteFilePath (mFile));
- void createActions();
- void setupDataFiles();
- void setupConfig();
- void readConfig();
+ success = file.exists();
+ }
- void loadSettings();
+ if (success)
+ return file.absoluteFilePath();
-};
+ return "";
+ }
+ };
+ };
+}
#endif
diff --git a/apps/launcher/graphicspage.cpp b/apps/launcher/graphicspage.cpp
index 9308c1d572..516c3d8233 100644
--- a/apps/launcher/graphicspage.cpp
+++ b/apps/launcher/graphicspage.cpp
@@ -4,10 +4,12 @@
#include <QMessageBox>
#include <QDir>
-#ifdef __APPLE__
+#ifdef MAC_OS_X_VERSION_MIN_REQUIRED
+#undef MAC_OS_X_VERSION_MIN_REQUIRED
// We need to do this because of Qt: https://bugreports.qt-project.org/browse/QTBUG-22154
#define MAC_OS_X_VERSION_MIN_REQUIRED __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__
-#endif
+#endif // MAC_OS_X_VERSION_MIN_REQUIRED
+
#include <SDL.h>
#include <cstdlib>
@@ -17,7 +19,7 @@
#include <components/files/configurationmanager.hpp>
#include <components/files/ogreplugin.hpp>
-#include <components/fileorderlist/utils/naturalsort.hpp>
+#include <components/contentselector/model/naturalsort.hpp>
#include "settings/graphicssettings.hpp"
@@ -33,11 +35,12 @@ QString getAspect(int x, int y)
return QString(QString::number(xaspect) + ":" + QString::number(yaspect));
}
-GraphicsPage::GraphicsPage(Files::ConfigurationManager &cfg, GraphicsSettings &graphicsSetting, QWidget *parent)
+Launcher::GraphicsPage::GraphicsPage(Files::ConfigurationManager &cfg, GraphicsSettings &graphicsSetting, QWidget *parent)
: mCfgMgr(cfg)
, mGraphicsSettings(graphicsSetting)
, QWidget(parent)
{
+ setObjectName ("GraphicsPage");
setupUi(this);
// Set the maximum res we can set in windowed mode
@@ -52,7 +55,7 @@ GraphicsPage::GraphicsPage(Files::ConfigurationManager &cfg, GraphicsSettings &g
}
-bool GraphicsPage::setupOgre()
+bool Launcher::GraphicsPage::setupOgre()
{
// Create a log manager so we can surpress debug text to stdout/stderr
Ogre::LogManager* logMgr = OGRE_NEW Ogre::LogManager;
@@ -133,7 +136,7 @@ bool GraphicsPage::setupOgre()
msgBox.setIcon(QMessageBox::Critical);
msgBox.setStandardButtons(QMessageBox::Ok);
msgBox.setText(tr("<br><b>Could not select a valid render system</b><br><br> \
- Please make sure the plugins.cfg file exists and contains a valid rendering plugin.<br>"));
+ Please make sure Ogre plugins were installed correctly.<br>"));
msgBox.exec();
return false;
}
@@ -156,7 +159,7 @@ bool GraphicsPage::setupOgre()
return true;
}
-bool GraphicsPage::setupSDL()
+bool Launcher::GraphicsPage::setupSDL()
{
int displays = SDL_GetNumVideoDisplays();
@@ -179,7 +182,7 @@ bool GraphicsPage::setupSDL()
return true;
}
-bool GraphicsPage::loadSettings()
+bool Launcher::GraphicsPage::loadSettings()
{
if (!setupSDL())
return false;
@@ -218,7 +221,7 @@ bool GraphicsPage::loadSettings()
return true;
}
-void GraphicsPage::saveSettings()
+void Launcher::GraphicsPage::saveSettings()
{
vSyncCheckBox->checkState() ? mGraphicsSettings.setValue(QString("Video/vsync"), QString("true"))
: mGraphicsSettings.setValue(QString("Video/vsync"), QString("false"));
@@ -245,7 +248,7 @@ void GraphicsPage::saveSettings()
mGraphicsSettings.setValue(QString("Video/screen"), QString::number(screenComboBox->currentIndex()));
}
-QStringList GraphicsPage::getAvailableOptions(const QString &key, Ogre::RenderSystem *renderer)
+QStringList Launcher::GraphicsPage::getAvailableOptions(const QString &key, Ogre::RenderSystem *renderer)
{
QStringList result;
@@ -278,7 +281,7 @@ QStringList GraphicsPage::getAvailableOptions(const QString &key, Ogre::RenderSy
return result;
}
-QStringList GraphicsPage::getAvailableResolutions(int screen)
+QStringList Launcher::GraphicsPage::getAvailableResolutions(int screen)
{
QStringList result;
SDL_DisplayMode mode;
@@ -325,7 +328,7 @@ QStringList GraphicsPage::getAvailableResolutions(int screen)
return result;
}
-QRect GraphicsPage::getMaximumResolution()
+QRect Launcher::GraphicsPage::getMaximumResolution()
{
QRect max;
int screens = QApplication::desktop()->screenCount();
@@ -340,7 +343,7 @@ QRect GraphicsPage::getMaximumResolution()
return max;
}
-void GraphicsPage::rendererChanged(const QString &renderer)
+void Launcher::GraphicsPage::rendererChanged(const QString &renderer)
{
mSelectedRenderSystem = mOgre->getRenderSystemByName(renderer.toStdString());
@@ -349,7 +352,7 @@ void GraphicsPage::rendererChanged(const QString &renderer)
antiAliasingComboBox->addItems(getAvailableOptions(QString("FSAA"), mSelectedRenderSystem));
}
-void GraphicsPage::screenChanged(int screen)
+void Launcher::GraphicsPage::screenChanged(int screen)
{
if (screen >= 0) {
resolutionComboBox->clear();
@@ -357,7 +360,7 @@ void GraphicsPage::screenChanged(int screen)
}
}
-void GraphicsPage::slotFullScreenChanged(int state)
+void Launcher::GraphicsPage::slotFullScreenChanged(int state)
{
if (state == Qt::Checked) {
standardRadioButton->toggle();
@@ -371,7 +374,7 @@ void GraphicsPage::slotFullScreenChanged(int state)
}
}
-void GraphicsPage::slotStandardToggled(bool checked)
+void Launcher::GraphicsPage::slotStandardToggled(bool checked)
{
if (checked) {
resolutionComboBox->setEnabled(true);
diff --git a/apps/launcher/graphicspage.hpp b/apps/launcher/graphicspage.hpp
index d233ea12e2..7f5dcae1ee 100644
--- a/apps/launcher/graphicspage.hpp
+++ b/apps/launcher/graphicspage.hpp
@@ -18,49 +18,52 @@
#include "ui_graphicspage.h"
-class GraphicsSettings;
namespace Files { struct ConfigurationManager; }
-class GraphicsPage : public QWidget, private Ui::GraphicsPage
+namespace Launcher
{
- Q_OBJECT
-
-public:
- GraphicsPage(Files::ConfigurationManager &cfg, GraphicsSettings &graphicsSettings, QWidget *parent = 0);
-
- void saveSettings();
- bool loadSettings();
-
-public slots:
- void rendererChanged(const QString &renderer);
- void screenChanged(int screen);
-
-private slots:
- void slotFullScreenChanged(int state);
- void slotStandardToggled(bool checked);
-
-private:
- Ogre::Root *mOgre;
- Ogre::RenderSystem *mSelectedRenderSystem;
- Ogre::RenderSystem *mOpenGLRenderSystem;
- Ogre::RenderSystem *mDirect3DRenderSystem;
- #ifdef ENABLE_PLUGIN_GL
- Ogre::GLPlugin* mGLPlugin;
- #endif
- #ifdef ENABLE_PLUGIN_Direct3D9
- Ogre::D3D9Plugin* mD3D9Plugin;
- #endif
-
- Files::ConfigurationManager &mCfgMgr;
- GraphicsSettings &mGraphicsSettings;
-
- QStringList getAvailableOptions(const QString &key, Ogre::RenderSystem *renderer);
- QStringList getAvailableResolutions(int screen);
- QRect getMaximumResolution();
-
- bool setupOgre();
- bool setupSDL();
-};
-
+ class GraphicsSettings;
+
+ class GraphicsPage : public QWidget, private Ui::GraphicsPage
+ {
+ Q_OBJECT
+
+ public:
+ GraphicsPage(Files::ConfigurationManager &cfg, GraphicsSettings &graphicsSettings, QWidget *parent = 0);
+
+ void saveSettings();
+ bool loadSettings();
+
+ public slots:
+ void rendererChanged(const QString &renderer);
+ void screenChanged(int screen);
+
+ private slots:
+ void slotFullScreenChanged(int state);
+ void slotStandardToggled(bool checked);
+
+ private:
+ Ogre::Root *mOgre;
+ Ogre::RenderSystem *mSelectedRenderSystem;
+ Ogre::RenderSystem *mOpenGLRenderSystem;
+ Ogre::RenderSystem *mDirect3DRenderSystem;
+ #ifdef ENABLE_PLUGIN_GL
+ Ogre::GLPlugin* mGLPlugin;
+ #endif
+ #ifdef ENABLE_PLUGIN_Direct3D9
+ Ogre::D3D9Plugin* mD3D9Plugin;
+ #endif
+
+ Files::ConfigurationManager &mCfgMgr;
+ GraphicsSettings &mGraphicsSettings;
+
+ QStringList getAvailableOptions(const QString &key, Ogre::RenderSystem *renderer);
+ QStringList getAvailableResolutions(int screen);
+ QRect getMaximumResolution();
+
+ bool setupOgre();
+ bool setupSDL();
+ };
+}
#endif
diff --git a/apps/launcher/main.cpp b/apps/launcher/main.cpp
index f67f5edcff..9f89f28102 100644
--- a/apps/launcher/main.cpp
+++ b/apps/launcher/main.cpp
@@ -3,10 +3,12 @@
#include <QDir>
#include <QDebug>
-#ifdef __APPLE__
+#ifdef MAC_OS_X_VERSION_MIN_REQUIRED
+#undef MAC_OS_X_VERSION_MIN_REQUIRED
// We need to do this because of Qt: https://bugreports.qt-project.org/browse/QTBUG-22154
#define MAC_OS_X_VERSION_MIN_REQUIRED __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__
-#endif
+#endif // MAC_OS_X_VERSION_MIN_REQUIRED
+
#include <SDL.h>
#include "maindialog.hpp"
@@ -49,7 +51,7 @@ int main(int argc, char *argv[])
// Support non-latin characters
QTextCodec::setCodecForCStrings(QTextCodec::codecForName("UTF-8"));
- MainDialog mainWin;
+ Launcher::MainDialog mainWin;
if (mainWin.setup()) {
mainWin.show();
@@ -61,4 +63,3 @@ int main(int argc, char *argv[])
SDL_Quit();
return returnValue;
}
-
diff --git a/apps/launcher/maindialog.cpp b/apps/launcher/maindialog.cpp
index 032f70916f..4012a1fbd5 100644
--- a/apps/launcher/maindialog.cpp
+++ b/apps/launcher/maindialog.cpp
@@ -1,5 +1,6 @@
#include "maindialog.hpp"
+#include <QPushButton>
#include <QFontDatabase>
#include <QInputDialog>
#include <QFileDialog>
@@ -23,8 +24,8 @@
#include "graphicspage.hpp"
#include "datafilespage.hpp"
-MainDialog::MainDialog()
- : mGameSettings(mCfgMgr)
+Launcher::MainDialog::MainDialog(QWidget *parent)
+ : mGameSettings(mCfgMgr), QMainWindow (parent)
{
// Install the stylesheet font
QFile file;
@@ -69,7 +70,7 @@ MainDialog::MainDialog()
createIcons();
}
-void MainDialog::createIcons()
+void Launcher::MainDialog::createIcons()
{
if (!QIcon::hasThemeIcon("document-new"))
QIcon::setThemeName("tango");
@@ -101,15 +102,15 @@ void MainDialog::createIcons()
}
-void MainDialog::createPages()
+void Launcher::MainDialog::createPages()
{
mPlayPage = new PlayPage(this);
mGraphicsPage = new GraphicsPage(mCfgMgr, mGraphicsSettings, this);
mDataFilesPage = new DataFilesPage(mCfgMgr, mGameSettings, mLauncherSettings, this);
// Set the combobox of the play page to imitate the combobox on the datafilespage
- mPlayPage->setProfilesComboBoxModel(mDataFilesPage->profilesComboBoxModel());
- mPlayPage->setProfilesComboBoxIndex(mDataFilesPage->profilesComboBoxIndex());
+ mPlayPage->setProfilesModel(mDataFilesPage->profilesModel());
+ mPlayPage->setProfilesIndex(mDataFilesPage->profilesIndex());
// Add the pages to the stacked widget
pagesWidget->addWidget(mPlayPage);
@@ -121,12 +122,12 @@ void MainDialog::createPages()
connect(mPlayPage, SIGNAL(playButtonClicked()), this, SLOT(play()));
- connect(mPlayPage, SIGNAL(profileChanged(int)), mDataFilesPage, SLOT(setProfilesComboBoxIndex(int)));
- connect(mDataFilesPage, SIGNAL(profileChanged(int)), mPlayPage, SLOT(setProfilesComboBoxIndex(int)));
+ connect(mPlayPage, SIGNAL(signalProfileChanged(int)), mDataFilesPage, SLOT(slotProfileChanged(int)));
+ connect(mDataFilesPage, SIGNAL(signalProfileChanged(int)), mPlayPage, SLOT(setProfilesIndex(int)));
}
-bool MainDialog::showFirstRunDialog()
+bool Launcher::MainDialog::showFirstRunDialog()
{
QStringList iniPaths;
@@ -261,19 +262,11 @@ bool MainDialog::showFirstRunDialog()
// Add a new profile
if (msgBox.isChecked()) {
mLauncherSettings.setValue(QString("Profiles/currentprofile"), QString("Imported"));
+ mLauncherSettings.remove(QString("Profiles/Imported/content"));
- mLauncherSettings.remove(QString("Profiles/Imported/master"));
- mLauncherSettings.remove(QString("Profiles/Imported/plugin"));
-
- QStringList masters = mGameSettings.values(QString("master"));
- QStringList plugins = mGameSettings.values(QString("plugin"));
-
- foreach (const QString &master, masters) {
- mLauncherSettings.setMultiValue(QString("Profiles/Imported/master"), master);
- }
-
- foreach (const QString &plugin, plugins) {
- mLauncherSettings.setMultiValue(QString("Profiles/Imported/plugin"), plugin);
+ QStringList contents = mGameSettings.values(QString("content"));
+ foreach (const QString &content, contents) {
+ mLauncherSettings.setMultiValue(QString("Profiles/Imported/content"), content);
}
}
@@ -282,7 +275,7 @@ bool MainDialog::showFirstRunDialog()
return true;
}
-bool MainDialog::setup()
+bool Launcher::MainDialog::setup()
{
if (!setupLauncherSettings())
return false;
@@ -311,15 +304,33 @@ bool MainDialog::setup()
return true;
}
-void MainDialog::changePage(QListWidgetItem *current, QListWidgetItem *previous)
+void Launcher::MainDialog::changePage(QListWidgetItem *current, QListWidgetItem *previous)
{
if (!current)
current = previous;
- pagesWidget->setCurrentIndex(iconWidget->row(current));
+ int currentIndex = iconWidget->row(current);
+ int previousIndex = iconWidget->row(previous);
+
+ pagesWidget->setCurrentIndex(currentIndex);
+
+ DataFilesPage *previousPage = dynamic_cast<DataFilesPage *>(pagesWidget->widget(previousIndex));
+ DataFilesPage *currentPage = dynamic_cast<DataFilesPage *>(pagesWidget->widget(currentIndex));
+
+ //special call to update/save data files page list view when it's displayed/hidden.
+ if (previousPage)
+ {
+ if (previousPage->objectName() == "DataFilesPage")
+ previousPage->saveSettings();
+ }
+ else if (currentPage)
+ {
+ if (currentPage->objectName() == "DataFilesPage")
+ currentPage->loadSettings();
+ }
}
-bool MainDialog::setupLauncherSettings()
+bool Launcher::MainDialog::setupLauncherSettings()
{
mLauncherSettings.setMultiValueEnabled(true);
@@ -356,7 +367,7 @@ bool MainDialog::setupLauncherSettings()
}
#ifndef WIN32
-bool expansions(UnshieldThread& cd)
+bool Launcher::expansions(Launcher::UnshieldThread& cd)
{
if(cd.BloodmoonDone())
{
@@ -367,7 +378,7 @@ bool expansions(UnshieldThread& cd)
QMessageBox expansionsBox;
expansionsBox.setText(QObject::tr("<br>Would you like to install expansions now ? (make sure you have the disc)<br> \
If you want to install both Bloodmoon and Tribunal, you have to install Tribunal first.<br>"));
-
+
QAbstractButton* tribunalButton = NULL;
if(!cd.TribunalDone())
tribunalButton = expansionsBox.addButton(QObject::tr("&Tribunal"), QMessageBox::ActionRole);
@@ -386,7 +397,7 @@ bool expansions(UnshieldThread& cd)
{
TextSlotMsgBox cdbox;
- cdbox.setStandardButtons(QMessageBox::Cancel);
+ cdbox.setStandardButtons(QMessageBox::Cancel);
QObject::connect(&cd,SIGNAL(signalGUI(const QString&)), &cdbox, SLOT(setTextSlot(const QString&)));
QObject::connect(&cd,SIGNAL(close()), &cdbox, SLOT(reject()));
@@ -405,7 +416,7 @@ bool expansions(UnshieldThread& cd)
{
TextSlotMsgBox cdbox;
- cdbox.setStandardButtons(QMessageBox::Cancel);
+ cdbox.setStandardButtons(QMessageBox::Cancel);
QObject::connect(&cd,SIGNAL(signalGUI(const QString&)), &cdbox, SLOT(setTextSlot(const QString&)));
QObject::connect(&cd,SIGNAL(close()), &cdbox, SLOT(reject()));
@@ -427,7 +438,7 @@ bool expansions(UnshieldThread& cd)
}
#endif // WIN32
-bool MainDialog::setupGameSettings()
+bool Launcher::MainDialog::setupGameSettings()
{
QString userPath = QString::fromStdString(mCfgMgr.getUserPath().string());
QString globalPath = QString::fromStdString(mCfgMgr.getGlobalPath().string());
@@ -467,7 +478,7 @@ bool MainDialog::setupGameSettings()
foreach (const QString path, mGameSettings.getDataDirs()) {
QDir dir(path);
QStringList filters;
- filters << "*.esp" << "*.esm";
+ filters << "*.esp" << "*.esm" << "*.omwgame" << "*.omwaddon";
if (!dir.entryList(filters).isEmpty())
dataDirs.append(path);
@@ -485,12 +496,12 @@ bool MainDialog::setupGameSettings()
QAbstractButton *dirSelectButton =
msgBox.addButton(QObject::tr("Browse to &Install..."), QMessageBox::ActionRole);
-
+
#ifndef WIN32
- QAbstractButton *cdSelectButton =
+ QAbstractButton *cdSelectButton =
msgBox.addButton(QObject::tr("Browse to &CD..."), QMessageBox::ActionRole);
#endif
-
+
msgBox.exec();
@@ -505,14 +516,14 @@ bool MainDialog::setupGameSettings()
#ifndef WIN32
else if(msgBox.clickedButton() == cdSelectButton) {
UnshieldThread cd;
-
+
{
TextSlotMsgBox cdbox;
- cdbox.setStandardButtons(QMessageBox::Cancel);
+ cdbox.setStandardButtons(QMessageBox::Cancel);
QObject::connect(&cd,SIGNAL(signalGUI(const QString&)), &cdbox, SLOT(setTextSlot(const QString&)));
QObject::connect(&cd,SIGNAL(close()), &cdbox, SLOT(reject()));
-
+
cd.SetMorrowindPath(
QFileDialog::getOpenFileName(
NULL,
@@ -526,11 +537,11 @@ bool MainDialog::setupGameSettings()
QObject::tr("Select where to extract files to"),
QDir::currentPath(),
QFileDialog::ShowDirsOnly | QFileDialog::DontResolveSymlinks).toUtf8().constData());
-
+
cd.start();
cdbox.exec();
}
-
+
while(expansions(cd));
selectedFile = QString::fromStdString(cd.GetMWEsmPath());
@@ -550,7 +561,7 @@ bool MainDialog::setupGameSettings()
return true;
}
-bool MainDialog::setupGraphicsSettings()
+bool Launcher::MainDialog::setupGraphicsSettings()
{
mGraphicsSettings.setMultiValueEnabled(false);
@@ -604,7 +615,7 @@ bool MainDialog::setupGraphicsSettings()
return true;
}
-void MainDialog::loadSettings()
+void Launcher::MainDialog::loadSettings()
{
int width = mLauncherSettings.value(QString("General/MainWindow/width")).toInt();
int height = mLauncherSettings.value(QString("General/MainWindow/height")).toInt();
@@ -616,7 +627,7 @@ void MainDialog::loadSettings()
move(posX, posY);
}
-void MainDialog::saveSettings()
+void Launcher::MainDialog::saveSettings()
{
QString width = QString::number(this->width());
QString height = QString::number(this->height());
@@ -634,7 +645,7 @@ void MainDialog::saveSettings()
}
-bool MainDialog::writeSettings()
+bool Launcher::MainDialog::writeSettings()
{
// Now write all config files
saveSettings();
@@ -727,13 +738,13 @@ bool MainDialog::writeSettings()
return true;
}
-void MainDialog::closeEvent(QCloseEvent *event)
+void Launcher::MainDialog::closeEvent(QCloseEvent *event)
{
writeSettings();
event->accept();
}
-void MainDialog::play()
+void Launcher::MainDialog::play()
{
if (!writeSettings()) {
qApp->quit();
@@ -742,11 +753,11 @@ void MainDialog::play()
if(!mGameSettings.hasMaster()) {
QMessageBox msgBox;
- msgBox.setWindowTitle(tr("No master file selected"));
+ msgBox.setWindowTitle(tr("No game file selected"));
msgBox.setIcon(QMessageBox::Warning);
msgBox.setStandardButtons(QMessageBox::Ok);
- msgBox.setText(tr("<br><b>You do not have any master files selected.</b><br><br> \
- OpenMW will not start without a master file selected.<br>"));
+ msgBox.setText(tr("<br><b>You do not have no game file selected.</b><br><br> \
+ OpenMW will not start without a game file selected.<br>"));
msgBox.exec();
return;
}
@@ -756,7 +767,7 @@ void MainDialog::play()
qApp->quit();
}
-bool MainDialog::startProgram(const QString &name, const QStringList &arguments, bool detached)
+bool Launcher::MainDialog::startProgram(const QString &name, const QStringList &arguments, bool detached)
{
QString path = name;
#ifdef Q_OS_WIN
diff --git a/apps/launcher/maindialog.hpp b/apps/launcher/maindialog.hpp
index 824dff6e82..5b8e4908e7 100644
--- a/apps/launcher/maindialog.hpp
+++ b/apps/launcher/maindialog.hpp
@@ -11,57 +11,59 @@
#include "ui_mainwindow.h"
-class QListWidget;
class QListWidgetItem;
-class QStackedWidget;
-class QStringList;
-class QStringListModel;
-class QString;
-class PlayPage;
-class GraphicsPage;
-class DataFilesPage;
-
-class MainDialog : public QMainWindow, private Ui::MainWindow
+namespace Launcher
{
- Q_OBJECT
+ class PlayPage;
+ class GraphicsPage;
+ class DataFilesPage;
+ class UnshieldThread;
+
+#ifndef WIN32
+ bool expansions(Launcher::UnshieldThread& cd);
+#endif
-public:
- MainDialog();
- bool setup();
- bool showFirstRunDialog();
+ class MainDialog : public QMainWindow, private Ui::MainWindow
+ {
+ Q_OBJECT
-public slots:
- void changePage(QListWidgetItem *current, QListWidgetItem *previous);
- void play();
+ public:
+ explicit MainDialog(QWidget *parent = 0);
+ bool setup();
+ bool showFirstRunDialog();
-private:
- void createIcons();
- void createPages();
+ public slots:
+ void changePage(QListWidgetItem *current, QListWidgetItem *previous);
+ void play();
- bool setupLauncherSettings();
- bool setupGameSettings();
- bool setupGraphicsSettings();
+ private:
+ void createIcons();
+ void createPages();
- void loadSettings();
- void saveSettings();
- bool writeSettings();
+ bool setupLauncherSettings();
+ bool setupGameSettings();
+ bool setupGraphicsSettings();
- inline bool startProgram(const QString &name, bool detached = false) { return startProgram(name, QStringList(), detached); }
- bool startProgram(const QString &name, const QStringList &arguments, bool detached = false);
+ void loadSettings();
+ void saveSettings();
+ bool writeSettings();
- void closeEvent(QCloseEvent *event);
+ inline bool startProgram(const QString &name, bool detached = false) { return startProgram(name, QStringList(), detached); }
+ bool startProgram(const QString &name, const QStringList &arguments, bool detached = false);
- PlayPage *mPlayPage;
- GraphicsPage *mGraphicsPage;
- DataFilesPage *mDataFilesPage;
+ void closeEvent(QCloseEvent *event);
- Files::ConfigurationManager mCfgMgr;
+ PlayPage *mPlayPage;
+ GraphicsPage *mGraphicsPage;
+ DataFilesPage *mDataFilesPage;
- GameSettings mGameSettings;
- GraphicsSettings mGraphicsSettings;
- LauncherSettings mLauncherSettings;
+ Files::ConfigurationManager mCfgMgr;
-};
+ GameSettings mGameSettings;
+ GraphicsSettings mGraphicsSettings;
+ LauncherSettings mLauncherSettings;
+ };
+}
#endif
diff --git a/apps/launcher/playpage.cpp b/apps/launcher/playpage.cpp
index 46900c5958..6cfb9686fa 100644
--- a/apps/launcher/playpage.cpp
+++ b/apps/launcher/playpage.cpp
@@ -6,8 +6,9 @@
#include <QPlastiqueStyle>
#endif
-PlayPage::PlayPage(QWidget *parent) : QWidget(parent)
+Launcher::PlayPage::PlayPage(QWidget *parent) : QWidget(parent)
{
+ setObjectName ("PlayPage");
setupUi(this);
// Hacks to get the stylesheet look properly
@@ -17,27 +18,22 @@ PlayPage::PlayPage(QWidget *parent) : QWidget(parent)
#endif
profilesComboBox->setView(new QListView());
- connect(profilesComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(slotCurrentIndexChanged(int)));
+ connect(profilesComboBox, SIGNAL(activated(int)), this, SIGNAL (signalProfileChanged(int)));
connect(playButton, SIGNAL(clicked()), this, SLOT(slotPlayClicked()));
}
-void PlayPage::setProfilesComboBoxModel(QAbstractItemModel *model)
+void Launcher::PlayPage::setProfilesModel(QAbstractItemModel *model)
{
profilesComboBox->setModel(model);
}
-void PlayPage::setProfilesComboBoxIndex(int index)
+void Launcher::PlayPage::setProfilesIndex(int index)
{
profilesComboBox->setCurrentIndex(index);
}
-void PlayPage::slotCurrentIndexChanged(int index)
-{
- emit profileChanged(index);
-}
-
-void PlayPage::slotPlayClicked()
+void Launcher::PlayPage::slotPlayClicked()
{
emit playButtonClicked();
}
diff --git a/apps/launcher/playpage.hpp b/apps/launcher/playpage.hpp
index 4306396bd2..1dc5bb0fe0 100644
--- a/apps/launcher/playpage.hpp
+++ b/apps/launcher/playpage.hpp
@@ -9,27 +9,28 @@ class QComboBox;
class QPushButton;
class QAbstractItemModel;
-class PlayPage : public QWidget, private Ui::PlayPage
+namespace Launcher
{
- Q_OBJECT
+ class PlayPage : public QWidget, private Ui::PlayPage
+ {
+ Q_OBJECT
-public:
- PlayPage(QWidget *parent = 0);
- void setProfilesComboBoxModel(QAbstractItemModel *model);
+ public:
+ PlayPage(QWidget *parent = 0);
+ void setProfilesModel(QAbstractItemModel *model);
-signals:
- void profileChanged(int index);
- void playButtonClicked();
+ signals:
+ void signalProfileChanged(int index);
+ void playButtonClicked();
-public slots:
- void setProfilesComboBoxIndex(int index);
+ public slots:
+ void setProfilesIndex(int index);
-private slots:
- void slotCurrentIndexChanged(int index);
- void slotPlayClicked();
+ private slots:
+ void slotPlayClicked();
-};
-
+ };
+}
#endif
diff --git a/apps/launcher/settings/gamesettings.cpp b/apps/launcher/settings/gamesettings.cpp
index 205879bc37..41113c35aa 100644
--- a/apps/launcher/settings/gamesettings.cpp
+++ b/apps/launcher/settings/gamesettings.cpp
@@ -9,6 +9,7 @@
#include <components/files/configurationmanager.hpp>
#include <boost/version.hpp>
+
/**
* Workaround for problems with whitespaces in paths in older versions of Boost library
*/
@@ -26,16 +27,16 @@ namespace boost
#endif /* (BOOST_VERSION <= 104600) */
-GameSettings::GameSettings(Files::ConfigurationManager &cfg)
+Launcher::GameSettings::GameSettings(Files::ConfigurationManager &cfg)
: mCfgMgr(cfg)
{
}
-GameSettings::~GameSettings()
+Launcher::GameSettings::~GameSettings()
{
}
-void GameSettings::validatePaths()
+void Launcher::GameSettings::validatePaths()
{
if (mSettings.isEmpty() || !mDataDirs.isEmpty())
return; // Don't re-validate paths if they are already parsed
@@ -81,14 +82,14 @@ void GameSettings::validatePaths()
}
}
-QStringList GameSettings::values(const QString &key, const QStringList &defaultValues)
+QStringList Launcher::GameSettings::values(const QString &key, const QStringList &defaultValues)
{
if (!mSettings.values(key).isEmpty())
return mSettings.values(key);
return defaultValues;
}
-bool GameSettings::readFile(QTextStream &stream)
+bool Launcher::GameSettings::readFile(QTextStream &stream)
{
QMap<QString, QString> cache;
QRegExp keyRe("^([^=]+)\\s*=\\s*(.+)$");
@@ -130,7 +131,7 @@ bool GameSettings::readFile(QTextStream &stream)
return true;
}
-bool GameSettings::writeFile(QTextStream &stream)
+bool Launcher::GameSettings::writeFile(QTextStream &stream)
{
// Iterate in reverse order to preserve insertion order
QMapIterator<QString, QString> i(mSettings);
@@ -139,13 +140,13 @@ bool GameSettings::writeFile(QTextStream &stream)
while (i.hasPrevious()) {
i.previous();
- if (i.key() == QLatin1String("master") || i.key() == QLatin1String("plugin"))
+ if (i.key() == QLatin1String("content"))
continue;
// Quote paths with spaces
if (i.key() == QLatin1String("data")
- || i.key() == QLatin1String("data-local")
- || i.key() == QLatin1String("resources"))
+ || i.key() == QLatin1String("data-local")
+ || i.key() == QLatin1String("resources"))
{
if (i.value().contains(QChar(' ')))
{
@@ -161,15 +162,24 @@ bool GameSettings::writeFile(QTextStream &stream)
}
- QStringList masters = mSettings.values(QString("master"));
- for (int i = masters.count(); i--;) {
- stream << "master=" << masters.at(i) << "\n";
+ QStringList content = mSettings.values(QString("content"));
+ for (int i = content.count(); i--;) {
+ stream << "content=" << content.at(i) << "\n";
}
- QStringList plugins = mSettings.values(QString("plugin"));
- for (int i = plugins.count(); i--;) {
- stream << "plugin=" << plugins.at(i) << "\n";
+ return true;
+}
+
+bool Launcher::GameSettings::hasMaster()
+{
+ bool result = false;
+ QStringList content = mSettings.values(QString("content"));
+ for (int i = 0; i < content.count(); ++i) {
+ if (content.at(i).contains(".omwgame") || content.at(i).contains(".esm")) {
+ result = true;
+ break;
}
+ }
- return true;
+ return result;
}
diff --git a/apps/launcher/settings/gamesettings.hpp b/apps/launcher/settings/gamesettings.hpp
index 55b2107e2a..60236200a9 100644
--- a/apps/launcher/settings/gamesettings.hpp
+++ b/apps/launcher/settings/gamesettings.hpp
@@ -8,55 +8,61 @@
#include <boost/filesystem/path.hpp>
-namespace Files { typedef std::vector<boost::filesystem::path> PathContainer;
- struct ConfigurationManager;}
-
-class GameSettings
+namespace Files
{
-public:
- GameSettings(Files::ConfigurationManager &cfg);
- ~GameSettings();
+ typedef std::vector<boost::filesystem::path> PathContainer;
+ struct ConfigurationManager;
+}
- inline QString value(const QString &key, const QString &defaultValue = QString())
+namespace Launcher
+{
+ class GameSettings
{
- return mSettings.value(key).isEmpty() ? defaultValue : mSettings.value(key);
- }
+ public:
+ GameSettings(Files::ConfigurationManager &cfg);
+ ~GameSettings();
+ inline QString value(const QString &key, const QString &defaultValue = QString())
+ {
+ return mSettings.value(key).isEmpty() ? defaultValue : mSettings.value(key);
+ }
- inline void setValue(const QString &key, const QString &value)
- {
- mSettings.insert(key, value);
- }
- inline void setMultiValue(const QString &key, const QString &value)
- {
- QStringList values = mSettings.values(key);
- if (!values.contains(value))
- mSettings.insertMulti(key, value);
- }
+ inline void setValue(const QString &key, const QString &value)
+ {
+ mSettings.insert(key, value);
+ }
- inline void remove(const QString &key)
- {
- mSettings.remove(key);
- }
+ inline void setMultiValue(const QString &key, const QString &value)
+ {
+ QStringList values = mSettings.values(key);
+ if (!values.contains(value))
+ mSettings.insertMulti(key, value);
+ }
+
+ inline void remove(const QString &key)
+ {
+ mSettings.remove(key);
+ }
- inline QStringList getDataDirs() { return mDataDirs; }
- inline void addDataDir(const QString &dir) { if(!dir.isEmpty()) mDataDirs.append(dir); }
- inline QString getDataLocal() {return mDataLocal; }
- inline bool hasMaster() { return mSettings.count(QString("master")) > 0; }
+ inline QStringList getDataDirs() { return mDataDirs; }
+ inline void addDataDir(const QString &dir) { if(!dir.isEmpty()) mDataDirs.append(dir); }
+ inline QString getDataLocal() {return mDataLocal; }
- QStringList values(const QString &key, const QStringList &defaultValues = QStringList());
- bool readFile(QTextStream &stream);
- bool writeFile(QTextStream &stream);
+ bool hasMaster();
-private:
- Files::ConfigurationManager &mCfgMgr;
+ QStringList values(const QString &key, const QStringList &defaultValues = QStringList());
+ bool readFile(QTextStream &stream);
+ bool writeFile(QTextStream &stream);
- void validatePaths();
- QMap<QString, QString> mSettings;
+ private:
+ Files::ConfigurationManager &mCfgMgr;
- QStringList mDataDirs;
- QString mDataLocal;
-};
+ void validatePaths();
+ QMap<QString, QString> mSettings;
+ QStringList mDataDirs;
+ QString mDataLocal;
+ };
+}
#endif // GAMESETTINGS_HPP
diff --git a/apps/launcher/settings/graphicssettings.cpp b/apps/launcher/settings/graphicssettings.cpp
index 0c55800917..9dad3dee6b 100644
--- a/apps/launcher/settings/graphicssettings.cpp
+++ b/apps/launcher/settings/graphicssettings.cpp
@@ -5,15 +5,15 @@
#include <QRegExp>
#include <QMap>
-GraphicsSettings::GraphicsSettings()
+Launcher::GraphicsSettings::GraphicsSettings()
{
}
-GraphicsSettings::~GraphicsSettings()
+Launcher::GraphicsSettings::~GraphicsSettings()
{
}
-bool GraphicsSettings::writeFile(QTextStream &stream)
+bool Launcher::GraphicsSettings::writeFile(QTextStream &stream)
{
QString sectionPrefix;
QRegExp sectionRe("([^/]+)/(.+)$");
diff --git a/apps/launcher/settings/graphicssettings.hpp b/apps/launcher/settings/graphicssettings.hpp
index 3e8617849e..6f7c135473 100644
--- a/apps/launcher/settings/graphicssettings.hpp
+++ b/apps/launcher/settings/graphicssettings.hpp
@@ -3,14 +3,16 @@
#include "settingsbase.hpp"
-class GraphicsSettings : public SettingsBase<QMap<QString, QString> >
+namespace Launcher
{
-public:
- GraphicsSettings();
- ~GraphicsSettings();
+ class GraphicsSettings : public SettingsBase<QMap<QString, QString> >
+ {
+ public:
+ GraphicsSettings();
+ ~GraphicsSettings();
- bool writeFile(QTextStream &stream);
-
-};
+ bool writeFile(QTextStream &stream);
+ };
+}
#endif // GRAPHICSSETTINGS_HPP
diff --git a/apps/launcher/settings/launchersettings.cpp b/apps/launcher/settings/launchersettings.cpp
index 5d298e814e..705453555d 100644
--- a/apps/launcher/settings/launchersettings.cpp
+++ b/apps/launcher/settings/launchersettings.cpp
@@ -5,15 +5,17 @@
#include <QRegExp>
#include <QMap>
-LauncherSettings::LauncherSettings()
+#include <QDebug>
+
+Launcher::LauncherSettings::LauncherSettings()
{
}
-LauncherSettings::~LauncherSettings()
+Launcher::LauncherSettings::~LauncherSettings()
{
}
-QStringList LauncherSettings::values(const QString &key, Qt::MatchFlags flags)
+QStringList Launcher::LauncherSettings::values(const QString &key, Qt::MatchFlags flags)
{
QMap<QString, QString> settings = SettingsBase::getSettings();
@@ -34,7 +36,7 @@ QStringList LauncherSettings::values(const QString &key, Qt::MatchFlags flags)
return result;
}
-QStringList LauncherSettings::subKeys(const QString &key)
+QStringList Launcher::LauncherSettings::subKeys(const QString &key)
{
QMap<QString, QString> settings = SettingsBase::getSettings();
QStringList keys = settings.uniqueKeys();
@@ -44,12 +46,9 @@ QStringList LauncherSettings::subKeys(const QString &key)
QStringList result;
foreach (const QString &currentKey, keys) {
-
if (keyRe.indexIn(currentKey) != -1) {
-
QString prefixedKey = keyRe.cap(1);
if(prefixedKey.startsWith(key)) {
-
QString subKey = prefixedKey.remove(key);
if (!subKey.isEmpty())
result.append(subKey);
@@ -61,7 +60,7 @@ QStringList LauncherSettings::subKeys(const QString &key)
return result;
}
-bool LauncherSettings::writeFile(QTextStream &stream)
+bool Launcher::LauncherSettings::writeFile(QTextStream &stream)
{
QString sectionPrefix;
QRegExp sectionRe("([^/]+)/(.+)$");
diff --git a/apps/launcher/settings/launchersettings.hpp b/apps/launcher/settings/launchersettings.hpp
index 60c6f86bc7..8acc389a9d 100644
--- a/apps/launcher/settings/launchersettings.hpp
+++ b/apps/launcher/settings/launchersettings.hpp
@@ -3,17 +3,19 @@
#include "settingsbase.hpp"
-class LauncherSettings : public SettingsBase<QMap<QString, QString> >
+namespace Launcher
{
-public:
- LauncherSettings();
- ~LauncherSettings();
+ class LauncherSettings : public SettingsBase<QMap<QString, QString> >
+ {
+ public:
+ LauncherSettings();
+ ~LauncherSettings();
- QStringList subKeys(const QString &key);
- QStringList values(const QString &key, Qt::MatchFlags flags = Qt::MatchExactly);
+ QStringList subKeys(const QString &key);
+ QStringList values(const QString &key, Qt::MatchFlags flags = Qt::MatchExactly);
- bool writeFile(QTextStream &stream);
-
-};
+ bool writeFile(QTextStream &stream);
+ };
+}
#endif // LAUNCHERSETTINGS_HPP
diff --git a/apps/launcher/settings/settingsbase.hpp b/apps/launcher/settings/settingsbase.hpp
index ed8ada56c3..3a1cf8e30e 100644
--- a/apps/launcher/settings/settingsbase.hpp
+++ b/apps/launcher/settings/settingsbase.hpp
@@ -7,103 +7,105 @@
#include <QRegExp>
#include <QMap>
-template <class Map>
-class SettingsBase
+namespace Launcher
{
+ template <class Map>
+ class SettingsBase
+ {
-public:
- SettingsBase() { mMultiValue = false; }
- ~SettingsBase() {}
+ public:
+ SettingsBase() { mMultiValue = false; }
+ ~SettingsBase() {}
- inline QString value(const QString &key, const QString &defaultValue = QString())
- {
- return mSettings.value(key).isEmpty() ? defaultValue : mSettings.value(key);
- }
+ inline QString value(const QString &key, const QString &defaultValue = QString())
+ {
+ return mSettings.value(key).isEmpty() ? defaultValue : mSettings.value(key);
+ }
- inline void setValue(const QString &key, const QString &value)
- {
- QStringList values = mSettings.values(key);
- if (!values.contains(value))
- mSettings.insert(key, value);
- }
+ inline void setValue(const QString &key, const QString &value)
+ {
+ QStringList values = mSettings.values(key);
+ if (!values.contains(value))
+ mSettings.insert(key, value);
+ }
- inline void setMultiValue(const QString &key, const QString &value)
- {
- QStringList values = mSettings.values(key);
- if (!values.contains(value))
- mSettings.insertMulti(key, value);
- }
+ inline void setMultiValue(const QString &key, const QString &value)
+ {
+ QStringList values = mSettings.values(key);
+ if (!values.contains(value))
+ mSettings.insertMulti(key, value);
+ }
- inline void setMultiValueEnabled(bool enable)
- {
- mMultiValue = enable;
- }
+ inline void setMultiValueEnabled(bool enable)
+ {
+ mMultiValue = enable;
+ }
- inline void remove(const QString &key)
- {
- mSettings.remove(key);
- }
+ inline void remove(const QString &key)
+ {
+ mSettings.remove(key);
+ }
- Map getSettings() {return mSettings;}
+ Map getSettings() {return mSettings;}
- bool readFile(QTextStream &stream)
- {
- mCache.clear();
+ bool readFile(QTextStream &stream)
+ {
+ mCache.clear();
- QString sectionPrefix;
+ QString sectionPrefix;
- QRegExp sectionRe("^\\[([^]]+)\\]");
- QRegExp keyRe("^([^=]+)\\s*=\\s*(.+)$");
+ QRegExp sectionRe("^\\[([^]]+)\\]");
+ QRegExp keyRe("^([^=]+)\\s*=\\s*(.+)$");
- while (!stream.atEnd()) {
- QString line = stream.readLine();
+ while (!stream.atEnd()) {
+ QString line = stream.readLine();
- if (line.isEmpty() || line.startsWith("#"))
- continue;
+ if (line.isEmpty() || line.startsWith("#"))
+ continue;
- if (sectionRe.exactMatch(line)) {
- sectionPrefix = sectionRe.cap(1);
- sectionPrefix.append("/");
- continue;
- }
+ if (sectionRe.exactMatch(line)) {
+ sectionPrefix = sectionRe.cap(1);
+ sectionPrefix.append("/");
+ continue;
+ }
- if (keyRe.indexIn(line) != -1) {
+ if (keyRe.indexIn(line) != -1) {
- QString key = keyRe.cap(1).trimmed();
- QString value = keyRe.cap(2).trimmed();
+ QString key = keyRe.cap(1).trimmed();
+ QString value = keyRe.cap(2).trimmed();
- if (!sectionPrefix.isEmpty())
- key.prepend(sectionPrefix);
+ if (!sectionPrefix.isEmpty())
+ key.prepend(sectionPrefix);
- mSettings.remove(key);
+ mSettings.remove(key);
- QStringList values = mCache.values(key);
+ QStringList values = mCache.values(key);
- if (!values.contains(value)) {
- if (mMultiValue) {
- mCache.insertMulti(key, value);
- } else {
- mCache.insert(key, value);
+ if (!values.contains(value)) {
+ if (mMultiValue) {
+ mCache.insertMulti(key, value);
+ } else {
+ mCache.insert(key, value);
+ }
}
}
}
- }
- if (mSettings.isEmpty()) {
- mSettings = mCache; // This is the first time we read a file
+ if (mSettings.isEmpty()) {
+ mSettings = mCache; // This is the first time we read a file
+ return true;
+ }
+
+ // Merge the changed keys with those which didn't
+ mSettings.unite(mCache);
return true;
}
- // Merge the changed keys with those which didn't
- mSettings.unite(mCache);
- return true;
- }
-
-private:
- Map mSettings;
- Map mCache;
-
- bool mMultiValue;
-};
+ private:
+ Map mSettings;
+ Map mCache;
+ bool mMultiValue;
+ };
+}
#endif // SETTINGSBASE_HPP
diff --git a/apps/launcher/textslotmsgbox.cpp b/apps/launcher/textslotmsgbox.cpp
index 0607d1cc6e..62d9cf5761 100644
--- a/apps/launcher/textslotmsgbox.cpp
+++ b/apps/launcher/textslotmsgbox.cpp
@@ -1,6 +1,6 @@
#include "textslotmsgbox.hpp"
-void TextSlotMsgBox::setTextSlot(const QString& string)
+void Launcher::TextSlotMsgBox::setTextSlot(const QString& string)
{
setText(string);
}
diff --git a/apps/launcher/textslotmsgbox.hpp b/apps/launcher/textslotmsgbox.hpp
index a29e2c3543..a0fefaa253 100644
--- a/apps/launcher/textslotmsgbox.hpp
+++ b/apps/launcher/textslotmsgbox.hpp
@@ -3,11 +3,13 @@
#include <QMessageBox>
-class TextSlotMsgBox : public QMessageBox
+namespace Launcher
{
-Q_OBJECT
- public slots:
- void setTextSlot(const QString& string);
-};
-
+ class TextSlotMsgBox : public QMessageBox
+ {
+ Q_OBJECT
+ public slots:
+ void setTextSlot(const QString& string);
+ };
+}
#endif
diff --git a/apps/launcher/unshieldthread.cpp b/apps/launcher/unshieldthread.cpp
index ab9d984e1a..d0dbeb1bdb 100644
--- a/apps/launcher/unshieldthread.cpp
+++ b/apps/launcher/unshieldthread.cpp
@@ -77,6 +77,8 @@ namespace
ini.insert(loc, setting + "=" + val + "\r\n");
}
+ #define FIX(setting) add_setting(category, setting, get_setting(category, setting, inx), ini)
+
void bloodmoon_fix_ini(std::string& ini, const bfs::path inxPath)
{
std::string inx = read_to_string(inxPath);
@@ -88,95 +90,94 @@ namespace
ini.erase(start, end-start);
std::string category;
- std::string setting;
category = "General";
{
- setting = "Werewolf FOV"; add_setting(category, setting, get_setting(category, setting, inx), ini);
+ FIX("Werewolf FOV");
}
category = "Moons";
{
- setting = "Script Color"; add_setting(category, setting, get_setting(category, setting, inx), ini);
+ FIX("Script Color");
}
category = "Weather";
{
- setting = "Snow Ripples"; add_setting(category, setting, get_setting(category, setting, inx), ini);
- setting = "Snow Ripple Radius"; add_setting(category, setting, get_setting(category, setting, inx), ini);
- setting = "Snow Ripples Per Flake"; add_setting(category, setting, get_setting(category, setting, inx), ini);
- setting = "Snow Ripple Scale"; add_setting(category, setting, get_setting(category, setting, inx), ini);
- setting = "Snow Ripple Speed"; add_setting(category, setting, get_setting(category, setting, inx), ini);
- setting = "Snow Gravity Scale"; add_setting(category, setting, get_setting(category, setting, inx), ini);
- setting = "Snow High Kill"; add_setting(category, setting, get_setting(category, setting, inx), ini);
- setting = "Snow Low Kill"; add_setting(category, setting, get_setting(category, setting, inx), ini);
+ FIX("Snow Ripples");
+ FIX("Snow Ripple Radius");
+ FIX("Snow Ripples Per Flake");
+ FIX("Snow Ripple Scale");
+ FIX("Snow Ripple Speed");
+ FIX("Snow Gravity Scale");
+ FIX("Snow High Kill");
+ FIX("Snow Low Kill");
}
category = "Weather Blight";
{
- setting = "Ambient Loop Sound ID"; add_setting(category, setting, get_setting(category, setting, inx), ini);
+ FIX("Ambient Loop Sound ID");
}
category = "Weather Snow";
{
- setting = "Sky Sunrise Color"; add_setting(category, setting, get_setting(category, setting, inx), ini);
- setting = "Sky Day Color"; add_setting(category, setting, get_setting(category, setting, inx), ini);
- setting = "Sky Sunset Color"; add_setting(category, setting, get_setting(category, setting, inx), ini);
- setting = "Sky Night Color"; add_setting(category, setting, get_setting(category, setting, inx), ini);
- setting = "Fog Sunrise Color"; add_setting(category, setting, get_setting(category, setting, inx), ini);
- setting = "Fog Day Color"; add_setting(category, setting, get_setting(category, setting, inx), ini);
- setting = "Fog Sunset Color"; add_setting(category, setting, get_setting(category, setting, inx), ini);
- setting = "Fog Night Color"; add_setting(category, setting, get_setting(category, setting, inx), ini);
- setting = "Ambient Sunrise Color"; add_setting(category, setting, get_setting(category, setting, inx), ini);
- setting = "Ambient Day Color"; add_setting(category, setting, get_setting(category, setting, inx), ini);
- setting = "Ambient Sunset Color"; add_setting(category, setting, get_setting(category, setting, inx), ini);
- setting = "Ambient Night Color"; add_setting(category, setting, get_setting(category, setting, inx), ini);
- setting = "Sun Sunrise Color"; add_setting(category, setting, get_setting(category, setting, inx), ini);
- setting = "Sun Day Color"; add_setting(category, setting, get_setting(category, setting, inx), ini);
- setting = "Sun Sunset Color"; add_setting(category, setting, get_setting(category, setting, inx), ini);
- setting = "Sun Night Color"; add_setting(category, setting, get_setting(category, setting, inx), ini);
- setting = "Sun Disc Sunset Color"; add_setting(category, setting, get_setting(category, setting, inx), ini);
- setting = "Transition Delta"; add_setting(category, setting, get_setting(category, setting, inx), ini);
- setting = "Land Fog Day Depth"; add_setting(category, setting, get_setting(category, setting, inx), ini);
- setting = "Land Fog Night Depth"; add_setting(category, setting, get_setting(category, setting, inx), ini);
- setting = "Clouds Maximum Percent"; add_setting(category, setting, get_setting(category, setting, inx), ini);
- setting = "Wind Speed"; add_setting(category, setting, get_setting(category, setting, inx), ini);
- setting = "Cloud Speed"; add_setting(category, setting, get_setting(category, setting, inx), ini);
- setting = "Glare View"; add_setting(category, setting, get_setting(category, setting, inx), ini);
- setting = "Cloud Texture"; add_setting(category, setting, get_setting(category, setting, inx), ini);
- setting = "Ambient Loop Sound ID"; add_setting(category, setting, get_setting(category, setting, inx), ini);
- setting = "Snow Threshold"; add_setting(category, setting, get_setting(category, setting, inx), ini);
- setting = "Snow Diameter"; add_setting(category, setting, get_setting(category, setting, inx), ini);
- setting = "Snow Height Min"; add_setting(category, setting, get_setting(category, setting, inx), ini);
- setting = "Snow Height Max"; add_setting(category, setting, get_setting(category, setting, inx), ini);
- setting = "Snow Entrance Speed"; add_setting(category, setting, get_setting(category, setting, inx), ini);
- setting = "Max Snowflakes"; add_setting(category, setting, get_setting(category, setting, inx), ini);
+ FIX("Sky Sunrise Color");
+ FIX("Sky Day Color");
+ FIX("Sky Sunset Color");
+ FIX("Sky Night Color");
+ FIX("Fog Sunrise Color");
+ FIX("Fog Day Color");
+ FIX("Fog Sunset Color");
+ FIX("Fog Night Color");
+ FIX("Ambient Sunrise Color");
+ FIX("Ambient Day Color");
+ FIX("Ambient Sunset Color");
+ FIX("Ambient Night Color");
+ FIX("Sun Sunrise Color");
+ FIX("Sun Day Color");
+ FIX("Sun Sunset Color");
+ FIX("Sun Night Color");
+ FIX("Sun Disc Sunset Color");
+ FIX("Transition Delta");
+ FIX("Land Fog Day Depth");
+ FIX("Land Fog Night Depth");
+ FIX("Clouds Maximum Percent");
+ FIX("Wind Speed");
+ FIX("Cloud Speed");
+ FIX("Glare View");
+ FIX("Cloud Texture");
+ FIX("Ambient Loop Sound ID");
+ FIX("Snow Threshold");
+ FIX("Snow Diameter");
+ FIX("Snow Height Min");
+ FIX("Snow Height Max");
+ FIX("Snow Entrance Speed");
+ FIX("Max Snowflakes");
}
category = "Weather Blizzard";
{
- setting = "Sky Sunrise Color"; add_setting(category, setting, get_setting(category, setting, inx), ini);
- setting = "Sky Day Color"; add_setting(category, setting, get_setting(category, setting, inx), ini);
- setting = "Sky Sunset Color"; add_setting(category, setting, get_setting(category, setting, inx), ini);
- setting = "Sky Night Color"; add_setting(category, setting, get_setting(category, setting, inx), ini);
- setting = "Fog Sunrise Color"; add_setting(category, setting, get_setting(category, setting, inx), ini);
- setting = "Fog Day Color"; add_setting(category, setting, get_setting(category, setting, inx), ini);
- setting = "Fog Sunset Color"; add_setting(category, setting, get_setting(category, setting, inx), ini);
- setting = "Fog Night Color"; add_setting(category, setting, get_setting(category, setting, inx), ini);
- setting = "Ambient Sunrise Color"; add_setting(category, setting, get_setting(category, setting, inx), ini);
- setting = "Ambient Day Color"; add_setting(category, setting, get_setting(category, setting, inx), ini);
- setting = "Ambient Sunset Color"; add_setting(category, setting, get_setting(category, setting, inx), ini);
- setting = "Ambient Night Color"; add_setting(category, setting, get_setting(category, setting, inx), ini);
- setting = "Sun Sunrise Color"; add_setting(category, setting, get_setting(category, setting, inx), ini);
- setting = "Sun Day Color"; add_setting(category, setting, get_setting(category, setting, inx), ini);
- setting = "Sun Sunset Color"; add_setting(category, setting, get_setting(category, setting, inx), ini);
- setting = "Sun Night Color"; add_setting(category, setting, get_setting(category, setting, inx), ini);
- setting = "Sun Disc Sunset Color"; add_setting(category, setting, get_setting(category, setting, inx), ini);
- setting = "Transition Delta"; add_setting(category, setting, get_setting(category, setting, inx), ini);
- setting = "Land Fog Day Depth"; add_setting(category, setting, get_setting(category, setting, inx), ini);
- setting = "Land Fog Night Depth"; add_setting(category, setting, get_setting(category, setting, inx), ini);
- setting = "Clouds Maximum Percent"; add_setting(category, setting, get_setting(category, setting, inx), ini);
- setting = "Wind Speed"; add_setting(category, setting, get_setting(category, setting, inx), ini);
- setting = "Cloud Speed"; add_setting(category, setting, get_setting(category, setting, inx), ini);
- setting = "Glare View"; add_setting(category, setting, get_setting(category, setting, inx), ini);
- setting = "Cloud Texture"; add_setting(category, setting, get_setting(category, setting, inx), ini);
- setting = "Ambient Loop Sound ID"; add_setting(category, setting, get_setting(category, setting, inx), ini);
- setting = "Storm Threshold"; add_setting(category, setting, get_setting(category, setting, inx), ini);
+ FIX("Sky Sunrise Color");
+ FIX("Sky Day Color");
+ FIX("Sky Sunset Color");
+ FIX("Sky Night Color");
+ FIX("Fog Sunrise Color");
+ FIX("Fog Day Color");
+ FIX("Fog Sunset Color");
+ FIX("Fog Night Color");
+ FIX("Ambient Sunrise Color");
+ FIX("Ambient Day Color");
+ FIX("Ambient Sunset Color");
+ FIX("Ambient Night Color");
+ FIX("Sun Sunrise Color");
+ FIX("Sun Day Color");
+ FIX("Sun Sunset Color");
+ FIX("Sun Night Color");
+ FIX("Sun Disc Sunset Color");
+ FIX("Transition Delta");
+ FIX("Land Fog Day Depth");
+ FIX("Land Fog Night Depth");
+ FIX("Clouds Maximum Percent");
+ FIX("Wind Speed");
+ FIX("Cloud Speed");
+ FIX("Glare View");
+ FIX("Cloud Texture");
+ FIX("Ambient Loop Sound ID");
+ FIX("Storm Threshold");
}
}
@@ -216,7 +217,12 @@ namespace
else
{
if(copy)
- bfs::copy_file(dir->path(), to / dir->path().filename());
+ {
+ bfs::path dest = to / dir->path().filename();
+ if(bfs::exists(dest))
+ bfs::remove_all(dest);
+ bfs::copy_file(dir->path(), dest);
+ }
else
bfs::rename(dir->path(), to / dir->path().filename());
}
@@ -263,32 +269,53 @@ namespace
strptime(time, "%d %B %Y", &tms);
return mktime(&tms);
}
+
+ // Some cds have cab files which have the Data Files subfolders outside the Data Files folder
+ void install_dfiles_outside(const bfs::path& from, const bfs::path& dFiles)
+ {
+ bfs::path fonts = findFile(from, "fonts", false);
+ if(fonts.string() != "")
+ installToPath(fonts, dFiles / "Fonts");
+
+ bfs::path music = findFile(from, "music", false);
+ if(music.string() != "")
+ installToPath(music, dFiles / "Music");
+
+ bfs::path sound = findFile(from, "sound", false);
+ if(sound.string() != "")
+ installToPath(sound, dFiles / "Sound");
+
+ bfs::path splash = findFile(from, "splash", false);
+ if(splash.string() != "")
+ installToPath(splash, dFiles / "Splash");
+ }
+
}
-bool UnshieldThread::SetMorrowindPath(const std::string& path)
+bool Launcher::UnshieldThread::SetMorrowindPath(const std::string& path)
{
mMorrowindPath = path;
return true;
}
-bool UnshieldThread::SetTribunalPath(const std::string& path)
+bool Launcher::UnshieldThread::SetTribunalPath(const std::string& path)
{
mTribunalPath = path;
return true;
}
-bool UnshieldThread::SetBloodmoonPath(const std::string& path)
+bool Launcher::UnshieldThread::SetBloodmoonPath(const std::string& path)
{
mBloodmoonPath = path;
return true;
}
-void UnshieldThread::SetOutputPath(const std::string& path)
+void Launcher::UnshieldThread::SetOutputPath(const std::string& path)
{
mOutputPath = path;
}
-bool UnshieldThread::extract_file(Unshield* unshield, bfs::path output_dir, const char* prefix, int index)
+bool Launcher::UnshieldThread::extract_file(Unshield* unshield, bfs::path output_dir, const char* prefix, int index)
{
bool success;
bfs::path dirname;
@@ -322,7 +349,7 @@ bool UnshieldThread::extract_file(Unshield* unshield, bfs::path output_dir, cons
return success;
}
-void UnshieldThread::extract_cab(const bfs::path& cab, const bfs::path& output_dir, bool extract_ini)
+void Launcher::UnshieldThread::extract_cab(const bfs::path& cab, const bfs::path& output_dir, bool extract_ini)
{
Unshield * unshield;
unshield = unshield_open(cab.c_str());
@@ -342,7 +369,7 @@ void UnshieldThread::extract_cab(const bfs::path& cab, const bfs::path& output_d
}
-bool UnshieldThread::extract()
+bool Launcher::UnshieldThread::extract()
{
bfs::path outputDataFilesDir = mOutputPath;
outputDataFilesDir /= "Data Files";
@@ -360,6 +387,8 @@ bool UnshieldThread::extract()
installToPath(dFilesDir, outputDataFilesDir);
+ install_dfiles_outside(mwExtractPath, outputDataFilesDir);
+
// Videos are often kept uncompressed on the cd
bfs::path videosPath = findFile(mMorrowindPath.parent_path(), "video", false);
if(videosPath.string() != "")
@@ -394,6 +423,8 @@ bool UnshieldThread::extract()
installToPath(dFilesDir, outputDataFilesDir);
+ install_dfiles_outside(tbExtractPath, outputDataFilesDir);
+
// Mt GOTY CD has Sounds in a seperate folder from the rest of the data files
bfs::path soundsPath = findFile(tbExtractPath, "sounds", false);
if(soundsPath.string() != "")
@@ -421,6 +452,8 @@ bool UnshieldThread::extract()
bfs::path dFilesDir = findFile(bmExtractPath, "bloodmoon.esm").parent_path();
installToPath(dFilesDir, outputDataFilesDir);
+
+ install_dfiles_outside(bmExtractPath, outputDataFilesDir);
// My GOTY CD contains a folder within cab files called Tribunal patch,
// which contains Tribunal.esm
@@ -442,7 +475,7 @@ bool UnshieldThread::extract()
return true;
}
-void UnshieldThread::Done()
+void Launcher::UnshieldThread::Done()
{
// Get rid of unnecessary files
bfs::remove_all(mOutputPath / "extract-temp");
@@ -458,29 +491,30 @@ void UnshieldThread::Done()
bfs::last_write_time(findFile(mOutputPath, "bloodmoon.esm"), getTime("3 June 2003"));
}
-std::string UnshieldThread::GetMWEsmPath()
+std::string Launcher::UnshieldThread::GetMWEsmPath()
{
return findFile(mOutputPath / "Data Files", "morrowind.esm").string();
}
-bool UnshieldThread::TribunalDone()
+bool Launcher::UnshieldThread::TribunalDone()
{
return mTribunalDone;
}
-bool UnshieldThread::BloodmoonDone()
+bool Launcher::UnshieldThread::BloodmoonDone()
{
return mBloodmoonDone;
}
-void UnshieldThread::run()
+void Launcher::UnshieldThread::run()
{
extract();
emit close();
}
-UnshieldThread::UnshieldThread()
+Launcher::UnshieldThread::UnshieldThread()
{
+ unshield_set_log_level(0);
mMorrowindDone = false;
mTribunalDone = false;
mBloodmoonDone = false;
diff --git a/apps/launcher/unshieldthread.hpp b/apps/launcher/unshieldthread.hpp
index b48d3d9878..de6a32b442 100644
--- a/apps/launcher/unshieldthread.hpp
+++ b/apps/launcher/unshieldthread.hpp
@@ -7,51 +7,52 @@
#include <libunshield.h>
-
-class UnshieldThread : public QThread
+namespace Launcher
{
- Q_OBJECT
+ class UnshieldThread : public QThread
+ {
+ Q_OBJECT
+
+ public:
+ bool SetMorrowindPath(const std::string& path);
+ bool SetTribunalPath(const std::string& path);
+ bool SetBloodmoonPath(const std::string& path);
- public:
- bool SetMorrowindPath(const std::string& path);
- bool SetTribunalPath(const std::string& path);
- bool SetBloodmoonPath(const std::string& path);
+ void SetOutputPath(const std::string& path);
- void SetOutputPath(const std::string& path);
-
- bool extract();
+ bool extract();
- bool TribunalDone();
- bool BloodmoonDone();
+ bool TribunalDone();
+ bool BloodmoonDone();
- void Done();
+ void Done();
- std::string GetMWEsmPath();
+ std::string GetMWEsmPath();
- UnshieldThread();
+ UnshieldThread();
- private:
+ private:
- void extract_cab(const boost::filesystem::path& cab, const boost::filesystem::path& output_dir, bool extract_ini = false);
- bool extract_file(Unshield* unshield, boost::filesystem::path output_dir, const char* prefix, int index);
-
- boost::filesystem::path mMorrowindPath;
- boost::filesystem::path mTribunalPath;
- boost::filesystem::path mBloodmoonPath;
+ void extract_cab(const boost::filesystem::path& cab, const boost::filesystem::path& output_dir, bool extract_ini = false);
+ bool extract_file(Unshield* unshield, boost::filesystem::path output_dir, const char* prefix, int index);
- bool mMorrowindDone;
- bool mTribunalDone;
- bool mBloodmoonDone;
+ boost::filesystem::path mMorrowindPath;
+ boost::filesystem::path mTribunalPath;
+ boost::filesystem::path mBloodmoonPath;
- boost::filesystem::path mOutputPath;
+ bool mMorrowindDone;
+ bool mTribunalDone;
+ bool mBloodmoonDone;
+ boost::filesystem::path mOutputPath;
- protected:
- virtual void run();
- signals:
- void signalGUI(QString);
- void close();
-};
+ protected:
+ virtual void run();
+ signals:
+ void signalGUI(QString);
+ void close();
+ };
+}
#endif
diff --git a/apps/launcher/utils/checkablemessagebox.cpp b/apps/launcher/utils/checkablemessagebox.cpp
index 41207a8ded..2f775af57a 100644
--- a/apps/launcher/utils/checkablemessagebox.cpp
+++ b/apps/launcher/utils/checkablemessagebox.cpp
@@ -54,72 +54,61 @@
Emulates the QMessageBox API with
static conveniences. The message label can open external URLs.
*/
-
-class CheckableMessageBoxPrivate
-{
-public:
- CheckableMessageBoxPrivate(QDialog *q)
+Launcher::CheckableMessageBoxPrivate::CheckableMessageBoxPrivate(QDialog *q)
: clickedButton(0)
- {
- QSizePolicy sizePolicy(QSizePolicy::Minimum, QSizePolicy::Preferred);
-
- pixmapLabel = new QLabel(q);
- sizePolicy.setHorizontalStretch(0);
- sizePolicy.setVerticalStretch(0);
- sizePolicy.setHeightForWidth(pixmapLabel->sizePolicy().hasHeightForWidth());
- pixmapLabel->setSizePolicy(sizePolicy);
- pixmapLabel->setVisible(false);
-
- QSpacerItem *pixmapSpacer =
- new QSpacerItem(0, 5, QSizePolicy::Minimum, QSizePolicy::MinimumExpanding);
-
- messageLabel = new QLabel(q);
- messageLabel->setMinimumSize(QSize(300, 0));
- messageLabel->setWordWrap(true);
- messageLabel->setOpenExternalLinks(true);
- messageLabel->setTextInteractionFlags(Qt::LinksAccessibleByKeyboard|Qt::LinksAccessibleByMouse);
-
- QSpacerItem *checkBoxRightSpacer =
- new QSpacerItem(1, 1, QSizePolicy::Expanding, QSizePolicy::Minimum);
- QSpacerItem *buttonSpacer =
- new QSpacerItem(0, 1, QSizePolicy::Minimum, QSizePolicy::Minimum);
-
- checkBox = new QCheckBox(q);
- checkBox->setText(CheckableMessageBox::tr("Do not ask again"));
-
- buttonBox = new QDialogButtonBox(q);
- buttonBox->setOrientation(Qt::Horizontal);
- buttonBox->setStandardButtons(QDialogButtonBox::Cancel|QDialogButtonBox::Ok);
-
- QVBoxLayout *verticalLayout = new QVBoxLayout();
- verticalLayout->addWidget(pixmapLabel);
- verticalLayout->addItem(pixmapSpacer);
-
- QHBoxLayout *horizontalLayout_2 = new QHBoxLayout();
- horizontalLayout_2->addLayout(verticalLayout);
- horizontalLayout_2->addWidget(messageLabel);
-
- QHBoxLayout *horizontalLayout = new QHBoxLayout();
- horizontalLayout->addWidget(checkBox);
- horizontalLayout->addItem(checkBoxRightSpacer);
-
- QVBoxLayout *verticalLayout_2 = new QVBoxLayout(q);
- verticalLayout_2->addLayout(horizontalLayout_2);
- verticalLayout_2->addLayout(horizontalLayout);
- verticalLayout_2->addItem(buttonSpacer);
- verticalLayout_2->addWidget(buttonBox);
- }
-
- QLabel *pixmapLabel;
- QLabel *messageLabel;
- QCheckBox *checkBox;
- QDialogButtonBox *buttonBox;
- QAbstractButton *clickedButton;
-};
+{
+ QSizePolicy sizePolicy(QSizePolicy::Minimum, QSizePolicy::Preferred);
+
+ pixmapLabel = new QLabel(q);
+ sizePolicy.setHorizontalStretch(0);
+ sizePolicy.setVerticalStretch(0);
+ sizePolicy.setHeightForWidth(pixmapLabel->sizePolicy().hasHeightForWidth());
+ pixmapLabel->setSizePolicy(sizePolicy);
+ pixmapLabel->setVisible(false);
+
+ QSpacerItem *pixmapSpacer =
+ new QSpacerItem(0, 5, QSizePolicy::Minimum, QSizePolicy::MinimumExpanding);
+
+ messageLabel = new QLabel(q);
+ messageLabel->setMinimumSize(QSize(300, 0));
+ messageLabel->setWordWrap(true);
+ messageLabel->setOpenExternalLinks(true);
+ messageLabel->setTextInteractionFlags(Qt::LinksAccessibleByKeyboard|Qt::LinksAccessibleByMouse);
+
+ QSpacerItem *checkBoxRightSpacer =
+ new QSpacerItem(1, 1, QSizePolicy::Expanding, QSizePolicy::Minimum);
+ QSpacerItem *buttonSpacer =
+ new QSpacerItem(0, 1, QSizePolicy::Minimum, QSizePolicy::Minimum);
+
+ checkBox = new QCheckBox(q);
+ checkBox->setText(Launcher::CheckableMessageBox::tr("Do not ask again"));
+
+ buttonBox = new QDialogButtonBox(q);
+ buttonBox->setOrientation(Qt::Horizontal);
+ buttonBox->setStandardButtons(QDialogButtonBox::Cancel|QDialogButtonBox::Ok);
+
+ QVBoxLayout *verticalLayout = new QVBoxLayout();
+ verticalLayout->addWidget(pixmapLabel);
+ verticalLayout->addItem(pixmapSpacer);
+
+ QHBoxLayout *horizontalLayout_2 = new QHBoxLayout();
+ horizontalLayout_2->addLayout(verticalLayout);
+ horizontalLayout_2->addWidget(messageLabel);
+
+ QHBoxLayout *horizontalLayout = new QHBoxLayout();
+ horizontalLayout->addWidget(checkBox);
+ horizontalLayout->addItem(checkBoxRightSpacer);
+
+ QVBoxLayout *verticalLayout_2 = new QVBoxLayout(q);
+ verticalLayout_2->addLayout(horizontalLayout_2);
+ verticalLayout_2->addLayout(horizontalLayout);
+ verticalLayout_2->addItem(buttonSpacer);
+ verticalLayout_2->addWidget(buttonBox);
+}
-CheckableMessageBox::CheckableMessageBox(QWidget *parent) :
+Launcher::CheckableMessageBox::CheckableMessageBox(QWidget *parent) :
QDialog(parent),
- d(new CheckableMessageBoxPrivate(this))
+ d(new Launcher::CheckableMessageBoxPrivate(this))
{
setModal(true);
setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
@@ -129,102 +118,102 @@ CheckableMessageBox::CheckableMessageBox(QWidget *parent) :
SLOT(slotClicked(QAbstractButton*)));
}
-CheckableMessageBox::~CheckableMessageBox()
+Launcher::CheckableMessageBox::~CheckableMessageBox()
{
delete d;
}
-void CheckableMessageBox::slotClicked(QAbstractButton *b)
+void Launcher::CheckableMessageBox::slotClicked(QAbstractButton *b)
{
d->clickedButton = b;
}
-QAbstractButton *CheckableMessageBox::clickedButton() const
+QAbstractButton *Launcher::CheckableMessageBox::clickedButton() const
{
return d->clickedButton;
}
-QDialogButtonBox::StandardButton CheckableMessageBox::clickedStandardButton() const
+QDialogButtonBox::StandardButton Launcher::CheckableMessageBox::clickedStandardButton() const
{
if (d->clickedButton)
return d->buttonBox->standardButton(d->clickedButton);
return QDialogButtonBox::NoButton;
}
-QString CheckableMessageBox::text() const
+QString Launcher::CheckableMessageBox::text() const
{
return d->messageLabel->text();
}
-void CheckableMessageBox::setText(const QString &t)
+void Launcher::CheckableMessageBox::setText(const QString &t)
{
d->messageLabel->setText(t);
}
-QPixmap CheckableMessageBox::iconPixmap() const
+QPixmap Launcher::CheckableMessageBox::iconPixmap() const
{
if (const QPixmap *p = d->pixmapLabel->pixmap())
return QPixmap(*p);
return QPixmap();
}
-void CheckableMessageBox::setIconPixmap(const QPixmap &p)
+void Launcher::CheckableMessageBox::setIconPixmap(const QPixmap &p)
{
d->pixmapLabel->setPixmap(p);
d->pixmapLabel->setVisible(!p.isNull());
}
-bool CheckableMessageBox::isChecked() const
+bool Launcher::CheckableMessageBox::isChecked() const
{
return d->checkBox->isChecked();
}
-void CheckableMessageBox::setChecked(bool s)
+void Launcher::CheckableMessageBox::setChecked(bool s)
{
d->checkBox->setChecked(s);
}
-QString CheckableMessageBox::checkBoxText() const
+QString Launcher::CheckableMessageBox::checkBoxText() const
{
return d->checkBox->text();
}
-void CheckableMessageBox::setCheckBoxText(const QString &t)
+void Launcher::CheckableMessageBox::setCheckBoxText(const QString &t)
{
d->checkBox->setText(t);
}
-bool CheckableMessageBox::isCheckBoxVisible() const
+bool Launcher::CheckableMessageBox::isCheckBoxVisible() const
{
return d->checkBox->isVisible();
}
-void CheckableMessageBox::setCheckBoxVisible(bool v)
+void Launcher::CheckableMessageBox::setCheckBoxVisible(bool v)
{
d->checkBox->setVisible(v);
}
-QDialogButtonBox::StandardButtons CheckableMessageBox::standardButtons() const
+QDialogButtonBox::StandardButtons Launcher::CheckableMessageBox::standardButtons() const
{
return d->buttonBox->standardButtons();
}
-void CheckableMessageBox::setStandardButtons(QDialogButtonBox::StandardButtons s)
+void Launcher::CheckableMessageBox::setStandardButtons(QDialogButtonBox::StandardButtons s)
{
d->buttonBox->setStandardButtons(s);
}
-QPushButton *CheckableMessageBox::button(QDialogButtonBox::StandardButton b) const
+QPushButton *Launcher::CheckableMessageBox::button(QDialogButtonBox::StandardButton b) const
{
return d->buttonBox->button(b);
}
-QPushButton *CheckableMessageBox::addButton(const QString &text, QDialogButtonBox::ButtonRole role)
+QPushButton *Launcher::CheckableMessageBox::addButton(const QString &text, QDialogButtonBox::ButtonRole role)
{
return d->buttonBox->addButton(text, role);
}
-QDialogButtonBox::StandardButton CheckableMessageBox::defaultButton() const
+QDialogButtonBox::StandardButton Launcher::CheckableMessageBox::defaultButton() const
{
foreach (QAbstractButton *b, d->buttonBox->buttons())
if (QPushButton *pb = qobject_cast<QPushButton *>(b))
@@ -233,7 +222,7 @@ QDialogButtonBox::StandardButton CheckableMessageBox::defaultButton() const
return QDialogButtonBox::NoButton;
}
-void CheckableMessageBox::setDefaultButton(QDialogButtonBox::StandardButton s)
+void Launcher::CheckableMessageBox::setDefaultButton(QDialogButtonBox::StandardButton s)
{
if (QPushButton *b = d->buttonBox->button(s)) {
b->setDefault(true);
@@ -242,7 +231,7 @@ void CheckableMessageBox::setDefaultButton(QDialogButtonBox::StandardButton s)
}
QDialogButtonBox::StandardButton
-CheckableMessageBox::question(QWidget *parent,
+Launcher::CheckableMessageBox::question(QWidget *parent,
const QString &title,
const QString &question,
const QString &checkBoxText,
@@ -263,7 +252,7 @@ CheckableMessageBox::question(QWidget *parent,
return mb.clickedStandardButton();
}
-QMessageBox::StandardButton CheckableMessageBox::dialogButtonBoxToMessageBoxButton(QDialogButtonBox::StandardButton db)
+QMessageBox::StandardButton Launcher::CheckableMessageBox::dialogButtonBoxToMessageBoxButton(QDialogButtonBox::StandardButton db)
{
return static_cast<QMessageBox::StandardButton>(int(db));
}
diff --git a/apps/launcher/utils/checkablemessagebox.hpp b/apps/launcher/utils/checkablemessagebox.hpp
index 93fd43fe1f..09a501b9c2 100644
--- a/apps/launcher/utils/checkablemessagebox.hpp
+++ b/apps/launcher/utils/checkablemessagebox.hpp
@@ -34,67 +34,83 @@
#include <QMessageBox>
#include <QDialog>
-class CheckableMessageBoxPrivate;
+class QCheckBox;
-class CheckableMessageBox : public QDialog
+namespace Launcher
{
- Q_OBJECT
- Q_PROPERTY(QString text READ text WRITE setText)
- Q_PROPERTY(QPixmap iconPixmap READ iconPixmap WRITE setIconPixmap)
- Q_PROPERTY(bool isChecked READ isChecked WRITE setChecked)
- Q_PROPERTY(QString checkBoxText READ checkBoxText WRITE setCheckBoxText)
- Q_PROPERTY(QDialogButtonBox::StandardButtons buttons READ standardButtons WRITE setStandardButtons)
- Q_PROPERTY(QDialogButtonBox::StandardButton defaultButton READ defaultButton WRITE setDefaultButton)
-
-public:
- explicit CheckableMessageBox(QWidget *parent);
- virtual ~CheckableMessageBox();
-
- static QDialogButtonBox::StandardButton
- question(QWidget *parent,
- const QString &title,
- const QString &question,
- const QString &checkBoxText,
- bool *checkBoxSetting,
- QDialogButtonBox::StandardButtons buttons = QDialogButtonBox::Yes|QDialogButtonBox::No,
- QDialogButtonBox::StandardButton defaultButton = QDialogButtonBox::No);
-
- QString text() const;
- void setText(const QString &);
-
- bool isChecked() const;
- void setChecked(bool s);
-
- QString checkBoxText() const;
- void setCheckBoxText(const QString &);
-
- bool isCheckBoxVisible() const;
- void setCheckBoxVisible(bool);
-
- QDialogButtonBox::StandardButtons standardButtons() const;
- void setStandardButtons(QDialogButtonBox::StandardButtons s);
- QPushButton *button(QDialogButtonBox::StandardButton b) const;
- QPushButton *addButton(const QString &text, QDialogButtonBox::ButtonRole role);
-
- QDialogButtonBox::StandardButton defaultButton() const;
- void setDefaultButton(QDialogButtonBox::StandardButton s);
-
- // See static QMessageBox::standardPixmap()
- QPixmap iconPixmap() const;
- void setIconPixmap (const QPixmap &p);
-
- // Query the result
- QAbstractButton *clickedButton() const;
- QDialogButtonBox::StandardButton clickedStandardButton() const;
-
- // Conversion convenience
- static QMessageBox::StandardButton dialogButtonBoxToMessageBoxButton(QDialogButtonBox::StandardButton);
-
-private slots:
- void slotClicked(QAbstractButton *b);
-
-private:
- CheckableMessageBoxPrivate *d;
-};
-
+ class CheckableMessageBoxPrivate
+ {
+ public:
+
+ QLabel *pixmapLabel;
+ QLabel *messageLabel;
+ QCheckBox *checkBox;
+ QDialogButtonBox *buttonBox;
+ QAbstractButton *clickedButton;
+
+ public:
+ CheckableMessageBoxPrivate(QDialog *q);
+ };
+
+ class CheckableMessageBox : public QDialog
+ {
+ Q_OBJECT
+ Q_PROPERTY(QString text READ text WRITE setText)
+ Q_PROPERTY(QPixmap iconPixmap READ iconPixmap WRITE setIconPixmap)
+ Q_PROPERTY(bool isChecked READ isChecked WRITE setChecked)
+ Q_PROPERTY(QString checkBoxText READ checkBoxText WRITE setCheckBoxText)
+ Q_PROPERTY(QDialogButtonBox::StandardButtons buttons READ standardButtons WRITE setStandardButtons)
+ Q_PROPERTY(QDialogButtonBox::StandardButton defaultButton READ defaultButton WRITE setDefaultButton)
+
+ public:
+ explicit CheckableMessageBox(QWidget *parent);
+ virtual ~CheckableMessageBox();
+
+ static QDialogButtonBox::StandardButton
+ question(QWidget *parent,
+ const QString &title,
+ const QString &question,
+ const QString &checkBoxText,
+ bool *checkBoxSetting,
+ QDialogButtonBox::StandardButtons buttons = QDialogButtonBox::Yes|QDialogButtonBox::No,
+ QDialogButtonBox::StandardButton defaultButton = QDialogButtonBox::No);
+
+ QString text() const;
+ void setText(const QString &);
+
+ bool isChecked() const;
+ void setChecked(bool s);
+
+ QString checkBoxText() const;
+ void setCheckBoxText(const QString &);
+
+ bool isCheckBoxVisible() const;
+ void setCheckBoxVisible(bool);
+
+ QDialogButtonBox::StandardButtons standardButtons() const;
+ void setStandardButtons(QDialogButtonBox::StandardButtons s);
+ QPushButton *button(QDialogButtonBox::StandardButton b) const;
+ QPushButton *addButton(const QString &text, QDialogButtonBox::ButtonRole role);
+
+ QDialogButtonBox::StandardButton defaultButton() const;
+ void setDefaultButton(QDialogButtonBox::StandardButton s);
+
+ // See static QMessageBox::standardPixmap()
+ QPixmap iconPixmap() const;
+ void setIconPixmap (const QPixmap &p);
+
+ // Query the result
+ QAbstractButton *clickedButton() const;
+ QDialogButtonBox::StandardButton clickedStandardButton() const;
+
+ // Conversion convenience
+ static QMessageBox::StandardButton dialogButtonBoxToMessageBoxButton(QDialogButtonBox::StandardButton);
+
+ private slots:
+ void slotClicked(QAbstractButton *b);
+
+ private:
+ CheckableMessageBoxPrivate *d;
+ };
+}
#endif // CHECKABLEMESSAGEBOX_HPP
diff --git a/components/fileorderlist/utils/lineedit.cpp b/apps/launcher/utils/lineedit.cpp
index b0f3395897..3487075808 100644
--- a/components/fileorderlist/utils/lineedit.cpp
+++ b/apps/launcher/utils/lineedit.cpp
@@ -1,11 +1,13 @@
-#include <QToolButton>
-#include <QStyle>
-
#include "lineedit.hpp"
LineEdit::LineEdit(QWidget *parent)
: QLineEdit(parent)
{
+ setupClearButton();
+}
+
+void LineEdit::setupClearButton()
+{
mClearButton = new QToolButton(this);
QPixmap pixmap(":images/clear.png");
mClearButton->setIcon(QIcon(pixmap));
@@ -15,13 +17,6 @@ LineEdit::LineEdit(QWidget *parent)
mClearButton->hide();
connect(mClearButton, SIGNAL(clicked()), this, SLOT(clear()));
connect(this, SIGNAL(textChanged(const QString&)), this, SLOT(updateClearButton(const QString&)));
- int frameWidth = style()->pixelMetric(QStyle::PM_DefaultFrameWidth);
-
- setObjectName(QString("LineEdit"));
- setStyleSheet(QString("LineEdit { padding-right: %1px; } ").arg(mClearButton->sizeHint().width() + frameWidth + 1));
- QSize msz = minimumSizeHint();
- setMinimumSize(qMax(msz.width(), mClearButton->sizeHint().height() + frameWidth * 2 + 2),
- qMax(msz.height(), mClearButton->sizeHint().height() + frameWidth * 2 + 2));
}
void LineEdit::resizeEvent(QResizeEvent *)
diff --git a/components/fileorderlist/utils/lineedit.hpp b/apps/launcher/utils/lineedit.hpp
index 14bd7b1b4c..2dd7da32bd 100644
--- a/components/fileorderlist/utils/lineedit.hpp
+++ b/apps/launcher/utils/lineedit.hpp
@@ -11,6 +11,9 @@
#define LINEEDIT_H
#include <QLineEdit>
+#include <QStyle>
+#include <QStylePainter>
+#include <QToolButton>
class QToolButton;
@@ -18,6 +21,8 @@ class LineEdit : public QLineEdit
{
Q_OBJECT
+ QString mPlaceholderText;
+
public:
LineEdit(QWidget *parent = 0);
@@ -27,8 +32,10 @@ protected:
private slots:
void updateClearButton(const QString &text);
-private:
+protected:
QToolButton *mClearButton;
+
+ void setupClearButton();
};
#endif // LIENEDIT_H
diff --git a/components/fileorderlist/utils/profilescombobox.cpp b/apps/launcher/utils/profilescombobox.cpp
index c3ff953ae0..c143307249 100644
--- a/components/fileorderlist/utils/profilescombobox.cpp
+++ b/apps/launcher/utils/profilescombobox.cpp
@@ -5,18 +5,12 @@
#include <QKeyEvent>
#include "profilescombobox.hpp"
-#include "comboboxlineedit.hpp"
ProfilesComboBox::ProfilesComboBox(QWidget *parent) :
- QComboBox(parent)
+ ContentSelectorView::ComboBox(parent)
{
- mValidator = new QRegExpValidator(QRegExp("^[a-zA-Z0-9_]*$"), this); // Alpha-numeric + underscore
- setEditEnabled(true);
- setValidator(mValidator);
- setCompleter(0);
-
- connect(this, SIGNAL(currentIndexChanged(int)), this,
- SLOT(slotIndexChanged(int)));
+ connect(this, SIGNAL(activated(int)), this,
+ SLOT(slotIndexChangedByUser(int)));
setInsertPolicy(QComboBox::NoInsert);
}
@@ -37,6 +31,7 @@ void ProfilesComboBox::setEditEnabled(bool editable)
setValidator(mValidator);
ComboBoxLineEdit *edit = new ComboBoxLineEdit(this);
+
setLineEdit(edit);
setCompleter(0);
@@ -45,6 +40,9 @@ void ProfilesComboBox::setEditEnabled(bool editable)
connect(lineEdit(), SIGNAL(textChanged(QString)), this,
SLOT(slotTextChanged(QString)));
+
+ connect (lineEdit(), SIGNAL(textChanged(QString)), this,
+ SIGNAL (signalProfileTextChanged (QString)));
}
void ProfilesComboBox::slotTextChanged(const QString &text)
@@ -82,11 +80,20 @@ void ProfilesComboBox::slotEditingFinished()
emit(profileRenamed(previous, current));
}
-void ProfilesComboBox::slotIndexChanged(int index)
+void ProfilesComboBox::slotIndexChangedByUser(int index)
{
if (index == -1)
return;
- emit(profileChanged(mOldProfile, currentText()));
- mOldProfile = itemText(index);
+ emit (signalProfileChanged(mOldProfile, currentText()));
+ mOldProfile = currentText();
+}
+
+ProfilesComboBox::ComboBoxLineEdit::ComboBoxLineEdit (QWidget *parent)
+ : LineEdit (parent)
+{
+ int frameWidth = style()->pixelMetric(QStyle::PM_DefaultFrameWidth);
+
+ setObjectName(QString("ComboBoxLineEdit"));
+ setStyleSheet(QString("ComboBoxLineEdit { background-color: transparent; padding-right: %1px; } ").arg(mClearButton->sizeHint().width() + frameWidth + 1));
}
diff --git a/apps/launcher/utils/profilescombobox.hpp b/apps/launcher/utils/profilescombobox.hpp
new file mode 100644
index 0000000000..7b83c41b2f
--- /dev/null
+++ b/apps/launcher/utils/profilescombobox.hpp
@@ -0,0 +1,47 @@
+#ifndef PROFILESCOMBOBOX_HPP
+#define PROFILESCOMBOBOX_HPP
+
+#include "components/contentselector/view/combobox.hpp"
+#include "lineedit.hpp"
+
+#include <QDebug>
+
+class QString;
+
+class ProfilesComboBox : public ContentSelectorView::ComboBox
+{
+ Q_OBJECT
+
+public:
+ class ComboBoxLineEdit : public LineEdit
+ {
+ public:
+ explicit ComboBoxLineEdit (QWidget *parent = 0);
+ };
+
+public:
+
+ explicit ProfilesComboBox(QWidget *parent = 0);
+ void setEditEnabled(bool editable);
+ void setCurrentProfile(int index)
+ {
+ ComboBox::setCurrentIndex(index);
+ mOldProfile = currentText();
+ }
+
+signals:
+ void signalProfileTextChanged(const QString &item);
+ void signalProfileChanged(const QString &previous, const QString &current);
+ void signalProfileChanged(int index);
+ void profileRenamed(const QString &oldName, const QString &newName);
+
+private slots:
+
+ void slotEditingFinished();
+ void slotIndexChangedByUser(int index);
+ void slotTextChanged(const QString &text);
+
+private:
+ QString mOldProfile;
+};
+#endif // PROFILESCOMBOBOX_HPP
diff --git a/apps/launcher/utils/textinputdialog.cpp b/apps/launcher/utils/textinputdialog.cpp
index a4b36b95ea..76cbe32d01 100644
--- a/apps/launcher/utils/textinputdialog.cpp
+++ b/apps/launcher/utils/textinputdialog.cpp
@@ -7,19 +7,18 @@
#include <QValidator>
#include <QLabel>
-#include <components/fileorderlist/utils/lineedit.hpp>
-
-TextInputDialog::TextInputDialog(const QString& title, const QString &text, QWidget *parent) :
+Launcher::TextInputDialog::TextInputDialog(const QString& title, const QString &text, QWidget *parent) :
QDialog(parent)
{
setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
mButtonBox = new QDialogButtonBox(this);
mButtonBox->addButton(QDialogButtonBox::Ok);
mButtonBox->addButton(QDialogButtonBox::Cancel);
+ mButtonBox->button(QDialogButtonBox::Ok)->setEnabled (false);
// Line edit
QValidator *validator = new QRegExpValidator(QRegExp("^[a-zA-Z0-9_]*$"), this); // Alpha-numeric + underscore
- mLineEdit = new LineEdit(this);
+ mLineEdit = new DialogLineEdit(this);
mLineEdit->setValidator(validator);
mLineEdit->setCompleter(0);
@@ -38,34 +37,51 @@ TextInputDialog::TextInputDialog(const QString& title, const QString &text, QWid
Q_UNUSED(title);
#endif
- setOkButtonEnabled(false);
setModal(true);
connect(mButtonBox, SIGNAL(accepted()), this, SLOT(accept()));
connect(mButtonBox, SIGNAL(rejected()), this, SLOT(reject()));
+ connect(mLineEdit, SIGNAL(textChanged(QString)), this, SLOT(slotUpdateOkButton(QString)));
}
-int TextInputDialog::exec()
+int Launcher::TextInputDialog::exec()
{
mLineEdit->clear();
mLineEdit->setFocus();
return QDialog::exec();
}
-void TextInputDialog::setOkButtonEnabled(bool enabled)
+QString Launcher::TextInputDialog::getText() const
{
- QPushButton *okButton = mButtonBox->button(QDialogButtonBox::Ok);
- okButton->setEnabled(enabled);
+ return mLineEdit->text();
+}
- QPalette *palette = new QPalette();
- palette->setColor(QPalette::Text,Qt::red);
+void Launcher::TextInputDialog::slotUpdateOkButton(QString text)
+{
+ bool enabled = !(text.isEmpty());
+ mButtonBox->button(QDialogButtonBox::Ok)->setEnabled(enabled);
- if (enabled) {
+ if (enabled)
mLineEdit->setPalette(QApplication::palette());
- } else {
+ else
+ {
// Existing profile name, make the text red
+ QPalette *palette = new QPalette();
+ palette->setColor(QPalette::Text,Qt::red);
mLineEdit->setPalette(*palette);
}
+}
+
+Launcher::TextInputDialog::DialogLineEdit::DialogLineEdit (QWidget *parent) :
+ LineEdit (parent)
+{
+ int frameWidth = style()->pixelMetric(QStyle::PM_DefaultFrameWidth);
+
+ setObjectName(QString("LineEdit"));
+ setStyleSheet(QString("LineEdit { padding-right: %1px; } ").arg(mClearButton->sizeHint().width() + frameWidth + 1));
+ QSize msz = minimumSizeHint();
+ setMinimumSize(qMax(msz.width(), mClearButton->sizeHint().height() + frameWidth * 2 + 2),
+ qMax(msz.height(), mClearButton->sizeHint().height() + frameWidth * 2 + 2));
}
diff --git a/apps/launcher/utils/textinputdialog.hpp b/apps/launcher/utils/textinputdialog.hpp
index cbb453ac83..bb01778be3 100644
--- a/apps/launcher/utils/textinputdialog.hpp
+++ b/apps/launcher/utils/textinputdialog.hpp
@@ -2,27 +2,39 @@
#define TEXTINPUTDIALOG_HPP
#include <QDialog>
-//#include "lineedit.hpp"
+
+#include "lineedit.hpp"
class QDialogButtonBox;
-class LineEdit;
-class TextInputDialog : public QDialog
+namespace Launcher
{
- Q_OBJECT
-public:
- explicit TextInputDialog(const QString& title, const QString &text, QWidget *parent = 0);
- inline LineEdit *lineEdit() { return mLineEdit; }
- void setOkButtonEnabled(bool enabled);
+ class TextInputDialog : public QDialog
+ {
+ Q_OBJECT
+
+ class DialogLineEdit : public LineEdit
+ {
+ public:
+ explicit DialogLineEdit (QWidget *parent = 0);
+ };
+
+ DialogLineEdit *mLineEdit;
+ QDialogButtonBox *mButtonBox;
+
+ public:
+
+ explicit TextInputDialog(const QString& title, const QString &text, QWidget *parent = 0);
+ ~TextInputDialog () {}
- LineEdit *mLineEdit;
+ QString getText() const;
- int exec();
+ int exec();
-private:
- QDialogButtonBox *mButtonBox;
+ private slots:
+ void slotUpdateOkButton(QString text);
-
-};
+ };
+}
#endif // TEXTINPUTDIALOG_HPP
diff --git a/apps/mwiniimporter/importer.cpp b/apps/mwiniimporter/importer.cpp
index 8732b3eab3..b8b7e4c9da 100644
--- a/apps/mwiniimporter/importer.cpp
+++ b/apps/mwiniimporter/importer.cpp
@@ -813,8 +813,7 @@ void MwIniImporter::importArchives(multistrmap &cfg, const multistrmap &ini) con
}
void MwIniImporter::importGameFiles(multistrmap &cfg, const multistrmap &ini) const {
- std::vector<std::string> esmFiles;
- std::vector<std::string> espFiles;
+ std::vector<std::string> contentFiles;
std::string baseGameFile("Game Files:GameFile");
std::string gameFile("");
@@ -832,29 +831,19 @@ void MwIniImporter::importGameFiles(multistrmap &cfg, const multistrmap &ini) co
std::string filetype(entry->substr(entry->length()-3));
Misc::StringUtils::toLower(filetype);
- if(filetype.compare("esm") == 0) {
- esmFiles.push_back(*entry);
- }
- else if(filetype.compare("esp") == 0) {
- espFiles.push_back(*entry);
+ if(filetype.compare("esm") == 0 || filetype.compare("esp") == 0) {
+ contentFiles.push_back(*entry);
}
}
gameFile = "";
}
- cfg.erase("master");
- cfg.insert( std::make_pair<std::string, std::vector<std::string> > ("master", std::vector<std::string>() ) );
-
- for(std::vector<std::string>::const_iterator it=esmFiles.begin(); it!=esmFiles.end(); ++it) {
- cfg["master"].push_back(*it);
- }
-
- cfg.erase("plugin");
- cfg.insert( std::make_pair<std::string, std::vector<std::string> > ("plugin", std::vector<std::string>() ) );
+ cfg.erase("content");
+ cfg.insert( std::make_pair("content", std::vector<std::string>() ) );
- for(std::vector<std::string>::const_iterator it=espFiles.begin(); it!=espFiles.end(); ++it) {
- cfg["plugin"].push_back(*it);
+ for(std::vector<std::string>::const_iterator it=contentFiles.begin(); it!=contentFiles.end(); ++it) {
+ cfg["content"].push_back(*it);
}
}
diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt
index fe0415ac08..f87650b331 100644
--- a/apps/opencs/CMakeLists.txt
+++ b/apps/opencs/CMakeLists.txt
@@ -5,11 +5,11 @@ opencs_units (. editor)
set (CMAKE_BUILD_TYPE DEBUG)
opencs_units (model/doc
- document
+ document operation saving
)
opencs_units_noqt (model/doc
- documentmanager
+ documentmanager stage savingstate savingstages
)
opencs_hdrs_noqt (model/doc
@@ -18,12 +18,12 @@ opencs_hdrs_noqt (model/doc
opencs_units (model/world
- idtable idtableproxymodel regionmap
+ idtable idtableproxymodel regionmap data
)
opencs_units_noqt (model/world
- universalid data record commands columnbase scriptcontext cell refidcollection
+ universalid record commands columnbase scriptcontext cell refidcollection
refidadapter refiddata refidadapterimp ref collectionbase refcollection columns
)
@@ -33,17 +33,18 @@ opencs_hdrs_noqt (model/world
opencs_units (model/tools
- tools operation reportmodel
+ tools reportmodel
)
opencs_units_noqt (model/tools
- stage verifier mandatoryid skillcheck classcheck factioncheck racecheck soundcheck regioncheck
+ mandatoryid skillcheck classcheck factioncheck racecheck soundcheck regioncheck
birthsigncheck spellcheck
)
opencs_units (view/doc
- viewmanager view operations operation subview startup filedialog
+ viewmanager view operations operation subview startup filedialog newgame
+ filewidget adjusterwidget
)
@@ -58,13 +59,14 @@ opencs_hdrs_noqt (view/doc
opencs_units (view/world
table tablesubview scriptsubview util regionmapsubview tablebottombox creator genericcreator
- cellcreator referenceablecreator referencecreator
+ cellcreator referenceablecreator referencecreator scenesubview scenetoolbar scenetool
+ scenetoolmode
)
opencs_units_noqt (view/world
dialoguesubview subviews
- enumdelegate vartypedelegate recordstatusdelegate refidtypedelegate datadisplaydelegate
- scripthighlighter idvalidator
+ enumdelegate vartypedelegate recordstatusdelegate idtypedelegate datadisplaydelegate
+ scripthighlighter idvalidator dialoguecreator
)
@@ -122,11 +124,13 @@ opencs_units (view/filter
set (OPENCS_US
)
-set (OPENCS_RES ../../files/opencs/resources.qrc
- ../../files/launcher/launcher.qrc
+set (OPENCS_RES ${CMAKE_SOURCE_DIR}/files/opencs/resources.qrc
+ ${CMAKE_SOURCE_DIR}/files/launcher/launcher.qrc
)
-set (OPENCS_UI ../../files/ui/datafilespage.ui
+set (OPENCS_UI
+ ${CMAKE_SOURCE_DIR}/files/ui/contentselector.ui
+ ${CMAKE_SOURCE_DIR}/files/ui/filedialog.ui
)
source_group (opencs FILES ${OPENCS_SRC} ${OPENCS_HDR})
@@ -144,15 +148,46 @@ qt4_add_resources(OPENCS_RES_SRC ${OPENCS_RES})
include_directories(${CMAKE_CURRENT_BINARY_DIR})
+if(APPLE)
+ set (OPENCS_MAC_ICON ${CMAKE_SOURCE_DIR}/files/mac/opencs.icns)
+else()
+ set (OPENCS_MAC_ICON "")
+endif(APPLE)
+
add_executable(opencs
+ MACOSX_BUNDLE
${OPENCS_SRC}
${OPENCS_UI_HDR}
${OPENCS_MOC_SRC}
${OPENCS_RES_SRC}
+ ${OPENCS_MAC_ICON}
)
+if(APPLE)
+ set_target_properties(opencs PROPERTIES
+ RUNTIME_OUTPUT_DIRECTORY "${OpenMW_BINARY_DIR}"
+ OUTPUT_NAME "OpenCS"
+ MACOSX_BUNDLE_ICON_FILE "opencs.icns"
+ MACOSX_BUNDLE_BUNDLE_NAME "OpenCS"
+ MACOSX_BUNDLE_GUI_IDENTIFIER "org.openmw.opencs"
+ MACOSX_BUNDLE_SHORT_VERSION_STRING ${OPENMW_VERSION}
+ MACOSX_BUNDLE_BUNDLE_VERSION ${OPENMW_VERSION}
+ )
+
+ set_source_files_properties(${OPENCS_MAC_ICON} PROPERTIES
+ MACOSX_PACKAGE_LOCATION Resources)
+endif(APPLE)
+
target_link_libraries(opencs
${Boost_LIBRARIES}
${QT_LIBRARIES}
components
)
+
+if(DPKG_PROGRAM)
+ INSTALL(TARGETS opencs RUNTIME DESTINATION games COMPONENT opencs)
+endif()
+
+if(APPLE)
+ INSTALL(TARGETS opencs BUNDLE DESTINATION OpenMW COMPONENT BUNDLE)
+endif()
diff --git a/apps/opencs/editor.cpp b/apps/opencs/editor.cpp
index 36d4f9735c..e879cb25e8 100644
--- a/apps/opencs/editor.cpp
+++ b/apps/opencs/editor.cpp
@@ -4,64 +4,97 @@
#include <QApplication>
#include <QLocalServer>
#include <QLocalSocket>
+#include <QMessageBox>
#include "model/doc/document.hpp"
#include "model/world/data.hpp"
+#include <iostream>
-CS::Editor::Editor() : mViewManager (mDocumentManager)
+CS::Editor::Editor()
+ : mDocumentManager (mCfgMgr), mViewManager (mDocumentManager)
{
- mIpcServerName = "org.openmw.OpenCS";
+ mIpcServerName = "org.openmw.OpenCS";
- connect (&mViewManager, SIGNAL (newDocumentRequest ()), this, SLOT (createDocument ()));
+ setupDataFiles();
+
+ mNewGame.setLocalData (mLocal);
+ mFileDialog.setLocalData (mLocal);
+
+ connect (&mViewManager, SIGNAL (newGameRequest ()), this, SLOT (createGame ()));
+ connect (&mViewManager, SIGNAL (newAddonRequest ()), this, SLOT (createAddon ()));
connect (&mViewManager, SIGNAL (loadDocumentRequest ()), this, SLOT (loadDocument ()));
+ connect (&mViewManager, SIGNAL (editSettingsRequest()), this, SLOT (showSettings ()));
- connect (&mStartup, SIGNAL (createDocument()), this, SLOT (createDocument ()));
+ connect (&mStartup, SIGNAL (createGame()), this, SLOT (createGame ()));
+ connect (&mStartup, SIGNAL (createAddon()), this, SLOT (createAddon ()));
connect (&mStartup, SIGNAL (loadDocument()), this, SLOT (loadDocument ()));
+ connect (&mStartup, SIGNAL (editConfig()), this, SLOT (showSettings ()));
- connect (&mFileDialog, SIGNAL(openFiles()), this, SLOT(openFiles()));
- connect (&mFileDialog, SIGNAL(createNewFile()), this, SLOT(createNewFile()));
+ connect (&mFileDialog, SIGNAL(signalOpenFiles (const boost::filesystem::path&)),
+ this, SLOT(openFiles (const boost::filesystem::path&)));
- setupDataFiles();
+ connect (&mFileDialog, SIGNAL(signalCreateNewFile (const boost::filesystem::path&)),
+ this, SLOT(createNewFile (const boost::filesystem::path&)));
+
+ connect (&mNewGame, SIGNAL (createRequest (const boost::filesystem::path&)),
+ this, SLOT (createNewGame (const boost::filesystem::path&)));
}
void CS::Editor::setupDataFiles()
{
boost::program_options::variables_map variables;
- boost::program_options::options_description desc;
+ boost::program_options::options_description desc("Syntax: opencs <options>\nAllowed options");
desc.add_options()
("data", boost::program_options::value<Files::PathContainer>()->default_value(Files::PathContainer(), "data")->multitoken())
("data-local", boost::program_options::value<std::string>()->default_value(""))
("fs-strict", boost::program_options::value<bool>()->implicit_value(true)->default_value(false))
- ("encoding", boost::program_options::value<std::string>()->default_value("win1252"));
+ ("encoding", boost::program_options::value<std::string>()->default_value("win1252"))
+ ("resources", boost::program_options::value<std::string>()->default_value("resources"));
boost::program_options::notify(variables);
mCfgMgr.readConfiguration(variables, desc);
- Files::PathContainer mDataDirs, mDataLocal;
+ Files::PathContainer dataDirs, dataLocal;
if (!variables["data"].empty()) {
- mDataDirs = Files::PathContainer(variables["data"].as<Files::PathContainer>());
+ dataDirs = Files::PathContainer(variables["data"].as<Files::PathContainer>());
}
std::string local = variables["data-local"].as<std::string>();
if (!local.empty()) {
- mDataLocal.push_back(Files::PathContainer::value_type(local));
+ dataLocal.push_back(Files::PathContainer::value_type(local));
}
- mCfgMgr.processPaths(mDataDirs);
- mCfgMgr.processPaths(mDataLocal);
+ mCfgMgr.processPaths (dataDirs);
+ mCfgMgr.processPaths (dataLocal, true);
+
+ if (!dataLocal.empty())
+ mLocal = dataLocal[0];
+ else
+ {
+ QMessageBox messageBox;
+ messageBox.setWindowTitle (tr ("No local data path available"));
+ messageBox.setIcon (QMessageBox::Critical);
+ messageBox.setStandardButtons (QMessageBox::Ok);
+ messageBox.setText(tr("<br><b>OpenCS is unable to access the local data directory. This may indicate a faulty configuration or a broken install.</b>"));
+ messageBox.exec();
+
+ QApplication::exit (1);
+ return;
+ }
// Set the charset for reading the esm/esp files
- QString encoding = QString::fromStdString(variables["encoding"].as<std::string>());
- mFileDialog.setEncoding(encoding);
+ // QString encoding = QString::fromStdString(variables["encoding"].as<std::string>());
+ //mFileDialog.setEncoding(encoding);
+
+ dataDirs.insert (dataDirs.end(), dataLocal.begin(), dataLocal.end());
- Files::PathContainer dataDirs;
- dataDirs.insert(dataDirs.end(), mDataDirs.begin(), mDataDirs.end());
- dataDirs.insert(dataDirs.end(), mDataLocal.begin(), mDataLocal.end());
+ mDocumentManager.setResourceDir (variables["resources"].as<std::string>());
for (Files::PathContainer::const_iterator iter = dataDirs.begin(); iter != dataDirs.end(); ++iter)
{
+
QString path = QString::fromStdString(iter->string());
mFileDialog.addFiles(path);
}
@@ -69,86 +102,116 @@ void CS::Editor::setupDataFiles()
//load the settings into the userSettings instance.
const QString settingFileName = "opencs.cfg";
CSMSettings::UserSettings::instance().loadSettings(settingFileName);
-
}
-void CS::Editor::createDocument()
+void CS::Editor::createGame()
{
mStartup.hide();
- mFileDialog.newFile();
+ if (mNewGame.isHidden())
+ mNewGame.show();
+
+ mNewGame.raise();
+ mNewGame.activateWindow();
}
-void CS::Editor::loadDocument()
+void CS::Editor::createAddon()
{
mStartup.hide();
+ mFileDialog.showDialog (CSVDoc::ContentAction_New);
+}
- mFileDialog.openFile();
+void CS::Editor::loadDocument()
+{
+ mStartup.hide();
+ mFileDialog.showDialog (CSVDoc::ContentAction_Edit);
}
-void CS::Editor::openFiles()
+void CS::Editor::openFiles (const boost::filesystem::path &savePath)
{
std::vector<boost::filesystem::path> files;
- QStringList paths = mFileDialog.checkedItemsPaths();
- foreach (const QString &path, paths) {
+ foreach (const QString &path, mFileDialog.selectedFilePaths())
files.push_back(path.toStdString());
- }
- CSMDoc::Document *document = mDocumentManager.addDocument(files, false);
+ CSMDoc::Document *document = mDocumentManager.addDocument (files, savePath, false);
mViewManager.addView (document);
mFileDialog.hide();
}
-void CS::Editor::createNewFile()
+void CS::Editor::createNewFile (const boost::filesystem::path &savePath)
{
std::vector<boost::filesystem::path> files;
- QStringList paths = mFileDialog.checkedItemsPaths();
- foreach (const QString &path, paths) {
+ foreach (const QString &path, mFileDialog.selectedFilePaths()) {
files.push_back(path.toStdString());
}
- files.push_back(mFileDialog.fileName().toStdString());
+ files.push_back(mFileDialog.filename().toStdString());
- CSMDoc::Document *document = mDocumentManager.addDocument (files, true);
+ CSMDoc::Document *document = mDocumentManager.addDocument (files, savePath, true);
mViewManager.addView (document);
mFileDialog.hide();
}
+void CS::Editor::createNewGame (const boost::filesystem::path& file)
+{
+ std::vector<boost::filesystem::path> files;
+
+ files.push_back (file);
+
+ CSMDoc::Document *document = mDocumentManager.addDocument (files, file, true);
+
+ mViewManager.addView (document);
+
+ mNewGame.hide();
+}
+
void CS::Editor::showStartup()
{
- if(mStartup.isHidden())
- mStartup.show();
- mStartup.raise();
- mStartup.activateWindow();
+ if(mStartup.isHidden())
+ mStartup.show();
+ mStartup.raise();
+ mStartup.activateWindow();
+}
+
+void CS::Editor::showSettings()
+{
+ if (mSettings.isHidden())
+ mSettings.show();
+
+ mSettings.raise();
+ mSettings.activateWindow();
}
bool CS::Editor::makeIPCServer()
{
- mServer = new QLocalServer(this);
+ mServer = new QLocalServer(this);
- if(mServer->listen(mIpcServerName))
- {
- connect(mServer, SIGNAL(newConnection()), this, SLOT(showStartup()));
- return true;
- }
+ if(mServer->listen(mIpcServerName))
+ {
+ connect(mServer, SIGNAL(newConnection()), this, SLOT(showStartup()));
+ return true;
+ }
- mServer->close();
- return false;
+ mServer->close();
+ return false;
}
void CS::Editor::connectToIPCServer()
{
- mClientSocket = new QLocalSocket(this);
- mClientSocket->connectToServer(mIpcServerName);
- mClientSocket->close();
+ mClientSocket = new QLocalSocket(this);
+ mClientSocket->connectToServer(mIpcServerName);
+ mClientSocket->close();
}
int CS::Editor::run()
{
+ if (mLocal.empty())
+ return 1;
+
mStartup.show();
QApplication::setQuitOnLastWindowClosed (true);
diff --git a/apps/opencs/editor.hpp b/apps/opencs/editor.hpp
index 80336d66f8..930aa9d643 100644
--- a/apps/opencs/editor.hpp
+++ b/apps/opencs/editor.hpp
@@ -9,12 +9,16 @@
#ifndef Q_MOC_RUN
#include <components/files/configurationmanager.hpp>
#endif
+
+#include "model/settings/usersettings.hpp"
#include "model/doc/documentmanager.hpp"
#include "view/doc/viewmanager.hpp"
#include "view/doc/startup.hpp"
#include "view/doc/filedialog.hpp"
-#include "model/settings/usersettings.hpp"
+#include "view/doc/newgame.hpp"
+
+#include "view/settings/usersettingsdialog.hpp"
namespace CS
{
@@ -22,13 +26,17 @@ namespace CS
{
Q_OBJECT
+ Files::ConfigurationManager mCfgMgr;
CSMSettings::UserSettings mUserSettings;
CSMDoc::DocumentManager mDocumentManager;
CSVDoc::ViewManager mViewManager;
CSVDoc::StartupDialogue mStartup;
- FileDialog mFileDialog;
+ CSVDoc::NewGameDialogue mNewGame;
+ CSVSettings::UserSettingsDialog mSettings;
+ CSVDoc::FileDialog mFileDialog;
+
+ boost::filesystem::path mLocal;
- Files::ConfigurationManager mCfgMgr;
void setupDataFiles();
// not implemented
@@ -47,14 +55,18 @@ namespace CS
private slots:
- void createDocument();
+ void createGame();
+ void createAddon();
void loadDocument();
- void openFiles();
- void createNewFile();
+ void openFiles (const boost::filesystem::path &path);
+ void createNewFile (const boost::filesystem::path& path);
+ void createNewGame (const boost::filesystem::path& file);
void showStartup();
+ void showSettings();
+
private:
QString mIpcServerName;
diff --git a/apps/opencs/main.cpp b/apps/opencs/main.cpp
index eddeb1983b..344a9360f6 100644
--- a/apps/opencs/main.cpp
+++ b/apps/opencs/main.cpp
@@ -7,6 +7,10 @@
#include <QApplication>
#include <QIcon>
+#ifdef Q_OS_MAC
+#include <QDir>
+#endif
+
class Application : public QApplication
{
private:
@@ -35,14 +39,33 @@ int main(int argc, char *argv[])
Q_INIT_RESOURCE (resources);
Application mApplication (argc, argv);
+#ifdef Q_OS_MAC
+ QDir dir(QCoreApplication::applicationDirPath());
+ if (dir.dirName() == "MacOS") {
+ dir.cdUp();
+ dir.cdUp();
+ dir.cdUp();
+ }
+ QDir::setCurrent(dir.absolutePath());
+
+ // force Qt to load only LOCAL plugins, don't touch system Qt installation
+ QDir pluginsPath(QCoreApplication::applicationDirPath());
+ pluginsPath.cdUp();
+ pluginsPath.cd("Plugins");
+
+ QStringList libraryPaths;
+ libraryPaths << pluginsPath.path() << QCoreApplication::applicationDirPath();
+ mApplication.setLibraryPaths(libraryPaths);
+#endif
+
mApplication.setWindowIcon (QIcon (":./opencs.png"));
CS::Editor editor;
if(!editor.makeIPCServer())
{
- editor.connectToIPCServer();
- return 0;
+ editor.connectToIPCServer();
+ // return 0;
}
return editor.run();
diff --git a/apps/opencs/model/doc/document.cpp b/apps/opencs/model/doc/document.cpp
index 30e9c21d12..27f4f498a4 100644
--- a/apps/opencs/model/doc/document.cpp
+++ b/apps/opencs/model/doc/document.cpp
@@ -1,8 +1,15 @@
#include "document.hpp"
+
#include <cassert>
+#include <boost/filesystem.hpp>
+
+#ifndef Q_MOC_RUN
+#include <components/files/configurationmanager.hpp>
+#endif
+
void CSMDoc::Document::load (const std::vector<boost::filesystem::path>::const_iterator& begin,
- const std::vector<boost::filesystem::path>::const_iterator& end, bool lastAsModified)
+ const std::vector<boost::filesystem::path>::const_iterator& end, bool lastAsModified)
{
assert (begin!=end);
@@ -12,10 +19,10 @@ void CSMDoc::Document::load (const std::vector<boost::filesystem::path>::const_i
--end2;
for (std::vector<boost::filesystem::path>::const_iterator iter (begin); iter!=end2; ++iter)
- getData().loadFile (*iter, true);
+ getData().loadFile (*iter, true, false);
if (lastAsModified)
- getData().loadFile (*end2, false);
+ getData().loadFile (*end2, false, false);
}
void CSMDoc::Document::addGmsts()
@@ -2058,9 +2065,9 @@ void CSMDoc::Document::addOptionalGlobals()
{
static const char *sGlobals[] =
{
- "dayspassed",
- "pcwerewolf",
- "pcyear",
+ "DaysPassed",
+ "PCWerewolf",
+ "PCYear",
0
};
@@ -2137,20 +2144,90 @@ void CSMDoc::Document::createBase()
getData().getSkills().add (record);
}
+
+ static const char *sVoice[] =
+ {
+ "Intruder",
+ "Attack",
+ "Hello",
+ "Thief",
+ "Alarm",
+ "Idle",
+ "Flee",
+ "Hit",
+ 0
+ };
+
+ for (int i=0; sVoice[i]; ++i)
+ {
+ ESM::Dialogue record;
+ record.mId = sVoice[i];
+ record.mType = ESM::Dialogue::Voice;
+ record.blank();
+
+ getData().getTopics().add (record);
+ }
+
+ static const char *sGreetings[] =
+ {
+ "Greeting 0",
+ "Greeting 1",
+ "Greeting 2",
+ "Greeting 3",
+ "Greeting 4",
+ "Greeting 5",
+ "Greeting 6",
+ "Greeting 7",
+ "Greeting 8",
+ "Greeting 9",
+ 0
+ };
+
+ for (int i=0; sGreetings[i]; ++i)
+ {
+ ESM::Dialogue record;
+ record.mId = sGreetings[i];
+ record.mType = ESM::Dialogue::Greeting;
+ record.blank();
+
+ getData().getTopics().add (record);
+ }
+
+ static const char *sPersuasion[] =
+ {
+ "Intimidate Success",
+ "Intimidate Fail",
+ "Service Refusal",
+ "Admire Success",
+ "Taunt Success",
+ "Bribe Success",
+ "Info Refusal",
+ "Admire Fail",
+ "Taunt Fail",
+ "Bribe Fail",
+ 0
+ };
+
+ for (int i=0; sPersuasion[i]; ++i)
+ {
+ ESM::Dialogue record;
+ record.mId = sPersuasion[i];
+ record.mType = ESM::Dialogue::Persuasion;
+ record.blank();
+
+ getData().getTopics().add (record);
+ }
}
-CSMDoc::Document::Document (const std::vector<boost::filesystem::path>& files, bool new_)
-: mTools (mData)
+CSMDoc::Document::Document (const Files::ConfigurationManager& configuration, const std::vector< boost::filesystem::path >& files, const boost::filesystem::path& savePath, const boost::filesystem::path& resDir, bool new_)
+ : mSavePath (savePath), mContentFiles (files), mTools (mData), mResDir(resDir),
+ mProjectPath ((configuration.getUserPath() / "projects") /
+ (savePath.filename().string() + ".project")),
+ mSaving (*this, mProjectPath)
{
if (files.empty())
throw std::runtime_error ("Empty content file sequence");
- /// \todo adjust last file name:
- /// \li make sure it is located in the data-local directory (adjust path if necessary)
- /// \li make sure the extension matches the new scheme (change it if necesarry)
-
- mName = files.back().filename().string();
-
if (new_ && files.size()==1)
createBase();
else
@@ -2163,6 +2240,44 @@ CSMDoc::Document::Document (const std::vector<boost::filesystem::path>& files, b
load (files.begin(), end, !new_);
}
+ if (new_)
+ {
+ mData.setDescription ("");
+ mData.setAuthor ("");
+ }
+
+ bool filtersFound = false;
+
+ if (boost::filesystem::exists (mProjectPath))
+ {
+ filtersFound = true;
+ }
+ else
+ {
+ boost::filesystem::path locCustomFiltersPath (configuration.getUserPath());
+ locCustomFiltersPath /= "defaultfilters";
+
+ if (boost::filesystem::exists(locCustomFiltersPath))
+ {
+ boost::filesystem::copy_file (locCustomFiltersPath, mProjectPath);
+ filtersFound = true;
+ }
+ else
+ {
+ boost::filesystem::path filters(mResDir);
+ filters /= "defaultfilters";
+
+ if (boost::filesystem::exists(filters))
+ {
+ boost::filesystem::copy_file(filters, mProjectPath);
+ filtersFound = true;
+ }
+ }
+ }
+
+ if (filtersFound)
+ getData().loadFile (mProjectPath, false, true);
+
addOptionalGmsts();
addOptionalGlobals();
@@ -2171,9 +2286,10 @@ CSMDoc::Document::Document (const std::vector<boost::filesystem::path>& files, b
connect (&mTools, SIGNAL (progress (int, int, int)), this, SLOT (progress (int, int, int)));
connect (&mTools, SIGNAL (done (int)), this, SLOT (operationDone (int)));
- // dummy implementation -> remove when proper save is implemented.
- mSaveCount = 0;
- connect (&mSaveTimer, SIGNAL(timeout()), this, SLOT (saving()));
+ connect (&mSaving, SIGNAL (progress (int, int, int)), this, SLOT (progress (int, int, int)));
+ connect (&mSaving, SIGNAL (done (int)), this, SLOT (operationDone (int)));
+ connect (&mSaving, SIGNAL (reportMessage (const QString&, int)),
+ this, SLOT (reportMessage (const QString&, int)));
}
CSMDoc::Document::~Document()
@@ -2192,7 +2308,7 @@ int CSMDoc::Document::getState() const
if (!mUndoStack.isClean())
state |= State_Modified;
- if (mSaveCount)
+ if (mSaving.isRunning())
state |= State_Locked | State_Saving | State_Operation;
if (int operations = mTools.getRunningOperations())
@@ -2201,17 +2317,25 @@ int CSMDoc::Document::getState() const
return state;
}
-const std::string& CSMDoc::Document::getName() const
+const boost::filesystem::path& CSMDoc::Document::getSavePath() const
{
- return mName;
+ return mSavePath;
+}
+
+const std::vector<boost::filesystem::path>& CSMDoc::Document::getContentFiles() const
+{
+ return mContentFiles;
}
void CSMDoc::Document::save()
{
- mSaveCount = 1;
- mSaveTimer.start (500);
+ if (mSaving.isRunning())
+ throw std::logic_error (
+ "Failed to initiate save, because a save operation is already running.");
+
+ mSaving.start();
+
emit stateChanged (getState(), this);
- emit progress (1, 16, State_Saving, 1, this);
}
CSMWorld::UniversalId CSMDoc::Document::verify()
@@ -2223,44 +2347,26 @@ CSMWorld::UniversalId CSMDoc::Document::verify()
void CSMDoc::Document::abortOperation (int type)
{
- mTools.abortOperation (type);
-
if (type==State_Saving)
- {
- mSaveCount=0;
- mSaveTimer.stop();
- emit stateChanged (getState(), this);
- }
+ mSaving.abort();
+ else
+ mTools.abortOperation (type);
}
-
void CSMDoc::Document::modificationStateChanged (bool clean)
{
emit stateChanged (getState(), this);
}
-
-void CSMDoc::Document::operationDone (int type)
+void CSMDoc::Document::reportMessage (const QString& message, int type)
{
- emit stateChanged (getState(), this);
+ /// \todo find a better way to get these messages to the user.
+ std::cout << message.toUtf8().constData() << std::endl;
}
-void CSMDoc::Document::saving()
+void CSMDoc::Document::operationDone (int type)
{
- ++mSaveCount;
-
- emit progress (mSaveCount, 16, State_Saving, 1, this);
-
- if (mSaveCount>15)
- {
- //clear the stack before resetting the save state
- //to avoid emitting incorrect states
- mUndoStack.setClean();
-
- mSaveCount = 0;
- mSaveTimer.stop();
- emit stateChanged (getState(), this);
- }
+ emit stateChanged (getState(), this);
}
const CSMWorld::Data& CSMDoc::Document::getData() const
diff --git a/apps/opencs/model/doc/document.hpp b/apps/opencs/model/doc/document.hpp
index 1c6d9db2a9..437b0c5131 100644
--- a/apps/opencs/model/doc/document.hpp
+++ b/apps/opencs/model/doc/document.hpp
@@ -14,6 +14,7 @@
#include "../tools/tools.hpp"
#include "state.hpp"
+#include "saving.hpp"
class QAbstractItemModel;
@@ -23,6 +24,11 @@ namespace ESM
struct Global;
}
+namespace Files
+{
+ class ConfigurationManager;
+}
+
namespace CSMDoc
{
class Document : public QObject
@@ -31,17 +37,18 @@ namespace CSMDoc
private:
- std::string mName; ///< \todo replace name with ESX list
+ boost::filesystem::path mSavePath;
+ std::vector<boost::filesystem::path> mContentFiles;
CSMWorld::Data mData;
CSMTools::Tools mTools;
+ boost::filesystem::path mProjectPath;
+ Saving mSaving;
+ boost::filesystem::path mResDir;
// It is important that the undo stack is declared last, because on desctruction it fires a signal, that is connected to a slot, that is
// using other member variables. Unfortunately this connection is cut only in the QObject destructor, which is way too late.
QUndoStack mUndoStack;
- int mSaveCount; ///< dummy implementation -> remove when proper save is implemented.
- QTimer mSaveTimer; ///< dummy implementation -> remove when proper save is implemented.
-
// not implemented
Document (const Document&);
Document& operator= (const Document&);
@@ -64,15 +71,19 @@ namespace CSMDoc
public:
- Document (const std::vector<boost::filesystem::path>& files, bool new_);
+ Document (const Files::ConfigurationManager& configuration, const std::vector< boost::filesystem::path >& files, const boost::filesystem::path& savePath, const boost::filesystem::path& resDir, bool new_);
+
~Document();
QUndoStack& getUndoStack();
int getState() const;
- const std::string& getName() const;
- ///< \todo replace with ESX list
+ const boost::filesystem::path& getSavePath() const;
+
+ const std::vector<boost::filesystem::path>& getContentFiles() const;
+ ///< \attention The last element in this collection is the file that is being edited,
+ /// but with its original path instead of the save path.
void save();
@@ -97,10 +108,9 @@ namespace CSMDoc
void modificationStateChanged (bool clean);
- void operationDone (int type);
+ void reportMessage (const QString& message, int type);
- void saving();
- ///< dummy implementation -> remove when proper save is implemented.
+ void operationDone (int type);
public slots:
@@ -109,3 +119,4 @@ namespace CSMDoc
}
#endif
+
diff --git a/apps/opencs/model/doc/documentmanager.cpp b/apps/opencs/model/doc/documentmanager.cpp
index 740c0b5827..024c46beae 100644
--- a/apps/opencs/model/doc/documentmanager.cpp
+++ b/apps/opencs/model/doc/documentmanager.cpp
@@ -4,9 +4,22 @@
#include <algorithm>
#include <stdexcept>
+#include <boost/filesystem.hpp>
+
+#ifndef Q_MOC_RUN
+#include <components/files/configurationmanager.hpp>
+#endif
+
#include "document.hpp"
-CSMDoc::DocumentManager::DocumentManager() {}
+CSMDoc::DocumentManager::DocumentManager (const Files::ConfigurationManager& configuration)
+: mConfiguration (configuration)
+{
+ boost::filesystem::path projectPath = configuration.getUserPath() / "projects";
+
+ if (!boost::filesystem::is_directory (projectPath))
+ boost::filesystem::create_directories (projectPath);
+}
CSMDoc::DocumentManager::~DocumentManager()
{
@@ -14,10 +27,10 @@ CSMDoc::DocumentManager::~DocumentManager()
delete *iter;
}
-CSMDoc::Document *CSMDoc::DocumentManager::addDocument (const std::vector<boost::filesystem::path>& files,
+CSMDoc::Document *CSMDoc::DocumentManager::addDocument (const std::vector<boost::filesystem::path>& files, const boost::filesystem::path& savePath,
bool new_)
{
- Document *document = new Document (files, new_);
+ Document *document = new Document (mConfiguration, files, savePath, mResDir, new_);
mDocuments.push_back (document);
@@ -35,4 +48,9 @@ bool CSMDoc::DocumentManager::removeDocument (Document *document)
delete document;
return mDocuments.empty();
+}
+
+void CSMDoc::DocumentManager::setResourceDir (const boost::filesystem::path& parResDir)
+{
+ mResDir = boost::filesystem::system_complete(parResDir);
} \ No newline at end of file
diff --git a/apps/opencs/model/doc/documentmanager.hpp b/apps/opencs/model/doc/documentmanager.hpp
index a307b76a57..b80a186429 100644
--- a/apps/opencs/model/doc/documentmanager.hpp
+++ b/apps/opencs/model/doc/documentmanager.hpp
@@ -6,6 +6,11 @@
#include <boost/filesystem/path.hpp>
+namespace Files
+{
+ class ConfigurationManager;
+}
+
namespace CSMDoc
{
class Document;
@@ -13,17 +18,18 @@ namespace CSMDoc
class DocumentManager
{
std::vector<Document *> mDocuments;
+ const Files::ConfigurationManager& mConfiguration;
DocumentManager (const DocumentManager&);
DocumentManager& operator= (const DocumentManager&);
public:
- DocumentManager();
+ DocumentManager (const Files::ConfigurationManager& configuration);
~DocumentManager();
- Document *addDocument (const std::vector<boost::filesystem::path>& files, bool new_);
+ Document *addDocument (const std::vector< boost::filesystem::path >& files, const boost::filesystem::path& savePath, bool new_);
///< The ownership of the returned document is not transferred to the caller.
///
/// \param new_ Do not load the last content file in \a files and instead create in an
@@ -31,6 +37,10 @@ namespace CSMDoc
bool removeDocument (Document *document);
///< \return last document removed?
+ void setResourceDir (const boost::filesystem::path& parResDir);
+
+ private:
+ boost::filesystem::path mResDir;
};
}
diff --git a/apps/opencs/model/tools/operation.cpp b/apps/opencs/model/doc/operation.cpp
index 71761cdaea..d29cc2631b 100644
--- a/apps/opencs/model/tools/operation.cpp
+++ b/apps/opencs/model/doc/operation.cpp
@@ -6,16 +6,16 @@
#include <QTimer>
-#include "../doc/state.hpp"
-
+#include "state.hpp"
#include "stage.hpp"
-void CSMTools::Operation::prepareStages()
+void CSMDoc::Operation::prepareStages()
{
mCurrentStage = mStages.begin();
mCurrentStep = 0;
mCurrentStepTotal = 0;
mTotalSteps = 0;
+ mError = false;
for (std::vector<std::pair<Stage *, int> >::iterator iter (mStages.begin()); iter!=mStages.end(); ++iter)
{
@@ -24,38 +24,61 @@ void CSMTools::Operation::prepareStages()
}
}
-CSMTools::Operation::Operation (int type) : mType (type) {}
+CSMDoc::Operation::Operation (int type, bool ordered, bool finalAlways)
+: mType (type), mOrdered (ordered), mFinalAlways (finalAlways)
+{
+ connect (this, SIGNAL (finished()), this, SLOT (operationDone()));
+}
-CSMTools::Operation::~Operation()
+CSMDoc::Operation::~Operation()
{
for (std::vector<std::pair<Stage *, int> >::iterator iter (mStages.begin()); iter!=mStages.end(); ++iter)
delete iter->first;
}
-void CSMTools::Operation::run()
+void CSMDoc::Operation::run()
{
prepareStages();
QTimer timer;
- timer.connect (&timer, SIGNAL (timeout()), this, SLOT (verify()));
+ timer.connect (&timer, SIGNAL (timeout()), this, SLOT (executeStage()));
timer.start (0);
exec();
}
-void CSMTools::Operation::appendStage (Stage *stage)
+void CSMDoc::Operation::appendStage (Stage *stage)
{
mStages.push_back (std::make_pair (stage, 0));
}
-void CSMTools::Operation::abort()
+bool CSMDoc::Operation::hasError() const
{
- exit();
+ return mError;
}
-void CSMTools::Operation::verify()
+void CSMDoc::Operation::abort()
+{
+ if (!isRunning())
+ return;
+
+ mError = true;
+
+ if (mFinalAlways)
+ {
+ if (mStages.begin()!=mStages.end() && mCurrentStage!=--mStages.end())
+ {
+ mCurrentStep = 0;
+ mCurrentStage = --mStages.end();
+ }
+ }
+ else
+ mCurrentStage = mStages.end();
+}
+
+void CSMDoc::Operation::executeStage()
{
std::vector<std::string> messages;
@@ -68,7 +91,16 @@ void CSMTools::Operation::verify()
}
else
{
- mCurrentStage->first->perform (mCurrentStep++, messages);
+ try
+ {
+ mCurrentStage->first->perform (mCurrentStep++, messages);
+ }
+ catch (const std::exception& e)
+ {
+ emit reportMessage (e.what(), mType);
+ abort();
+ }
+
++mCurrentStepTotal;
break;
}
@@ -81,4 +113,9 @@ void CSMTools::Operation::verify()
if (mCurrentStage==mStages.end())
exit();
+}
+
+void CSMDoc::Operation::operationDone()
+{
+ emit done (mType);
} \ No newline at end of file
diff --git a/apps/opencs/model/tools/operation.hpp b/apps/opencs/model/doc/operation.hpp
index 4731c58fa8..316eda78fd 100644
--- a/apps/opencs/model/tools/operation.hpp
+++ b/apps/opencs/model/doc/operation.hpp
@@ -1,11 +1,11 @@
-#ifndef CSM_TOOLS_OPERATION_H
-#define CSM_TOOLS_OPERATION_H
+#ifndef CSM_DOC_OPERATION_H
+#define CSM_DOC_OPERATION_H
#include <vector>
#include <QThread>
-namespace CSMTools
+namespace CSMDoc
{
class Stage;
@@ -19,12 +19,17 @@ namespace CSMTools
int mCurrentStep;
int mCurrentStepTotal;
int mTotalSteps;
+ int mOrdered;
+ bool mFinalAlways;
+ bool mError;
void prepareStages();
public:
- Operation (int type);
+ Operation (int type, bool ordered, bool finalAlways = false);
+ ///< \param ordered Stages must be executed in the given order.
+ /// \param finalAlways Execute last stage even if an error occurred during earlier stages.
virtual ~Operation();
@@ -35,19 +40,25 @@ namespace CSMTools
///
/// \attention Do no call this function while this Operation is running.
+ bool hasError() const;
+
signals:
void progress (int current, int max, int type);
void reportMessage (const QString& message, int type);
+ void done (int type);
+
public slots:
void abort();
private slots:
- void verify();
+ void executeStage();
+
+ void operationDone();
};
}
diff --git a/apps/opencs/model/doc/saving.cpp b/apps/opencs/model/doc/saving.cpp
new file mode 100644
index 0000000000..b756a9dc19
--- /dev/null
+++ b/apps/opencs/model/doc/saving.cpp
@@ -0,0 +1,74 @@
+
+#include "saving.hpp"
+
+#include "../world/data.hpp"
+#include "../world/idcollection.hpp"
+
+#include "state.hpp"
+#include "savingstages.hpp"
+#include "document.hpp"
+
+CSMDoc::Saving::Saving (Document& document, const boost::filesystem::path& projectPath)
+: Operation (State_Saving, true, true), mDocument (document), mState (*this, projectPath)
+{
+ // save project file
+ appendStage (new OpenSaveStage (mDocument, mState, true));
+
+ appendStage (new WriteHeaderStage (mDocument, mState, true));
+
+ appendStage (new WriteFilterStage (mDocument, mState, CSMFilter::Filter::Scope_Project));
+
+ appendStage (new CloseSaveStage (mState));
+
+ // save content file
+ appendStage (new OpenSaveStage (mDocument, mState, false));
+
+ appendStage (new WriteHeaderStage (mDocument, mState, false));
+
+ appendStage (new WriteCollectionStage<CSMWorld::IdCollection<ESM::Global> >
+ (mDocument.getData().getGlobals(), mState));
+
+ appendStage (new WriteCollectionStage<CSMWorld::IdCollection<ESM::GameSetting> >
+ (mDocument.getData().getGmsts(), mState));
+
+ appendStage (new WriteCollectionStage<CSMWorld::IdCollection<ESM::Skill> >
+ (mDocument.getData().getSkills(), mState));
+
+ appendStage (new WriteCollectionStage<CSMWorld::IdCollection<ESM::Class> >
+ (mDocument.getData().getClasses(), mState));
+
+ appendStage (new WriteCollectionStage<CSMWorld::IdCollection<ESM::Faction> >
+ (mDocument.getData().getFactions(), mState));
+
+ appendStage (new WriteCollectionStage<CSMWorld::IdCollection<ESM::Race> >
+ (mDocument.getData().getRaces(), mState));
+
+ appendStage (new WriteCollectionStage<CSMWorld::IdCollection<ESM::Sound> >
+ (mDocument.getData().getSounds(), mState));
+
+ appendStage (new WriteCollectionStage<CSMWorld::IdCollection<ESM::Script> >
+ (mDocument.getData().getScripts(), mState));
+
+ appendStage (new WriteCollectionStage<CSMWorld::IdCollection<ESM::Region> >
+ (mDocument.getData().getRegions(), mState));
+
+ appendStage (new WriteCollectionStage<CSMWorld::IdCollection<ESM::BirthSign> >
+ (mDocument.getData().getBirthsigns(), mState));
+
+ appendStage (new WriteCollectionStage<CSMWorld::IdCollection<ESM::Spell> >
+ (mDocument.getData().getSpells(), mState));
+
+ /// \todo deal with info records for topcis and journals
+ appendStage (new WriteCollectionStage<CSMWorld::IdCollection<ESM::Dialogue> >
+ (mDocument.getData().getTopics(), mState));
+
+ appendStage (new WriteCollectionStage<CSMWorld::IdCollection<ESM::Dialogue> >
+ (mDocument.getData().getJournals(), mState));
+
+ appendStage (new WriteRefIdCollectionStage (mDocument, mState));
+
+
+ appendStage (new CloseSaveStage (mState));
+
+ appendStage (new FinalSavingStage (mDocument, mState));
+} \ No newline at end of file
diff --git a/apps/opencs/model/doc/saving.hpp b/apps/opencs/model/doc/saving.hpp
new file mode 100644
index 0000000000..cd1bbef980
--- /dev/null
+++ b/apps/opencs/model/doc/saving.hpp
@@ -0,0 +1,27 @@
+#ifndef CSM_DOC_SAVING_H
+#define CSM_DOC_SAVING_H
+
+#include <boost/filesystem/path.hpp>
+
+#include "operation.hpp"
+#include "savingstate.hpp"
+
+namespace CSMDoc
+{
+ class Document;
+
+ class Saving : public Operation
+ {
+ Q_OBJECT
+
+ Document& mDocument;
+ SavingState mState;
+
+ public:
+
+ Saving (Document& document, const boost::filesystem::path& projectPath);
+
+ };
+}
+
+#endif
diff --git a/apps/opencs/model/doc/savingstages.cpp b/apps/opencs/model/doc/savingstages.cpp
new file mode 100644
index 0000000000..d68c723179
--- /dev/null
+++ b/apps/opencs/model/doc/savingstages.cpp
@@ -0,0 +1,161 @@
+
+#include "savingstages.hpp"
+
+#include <fstream>
+
+#include <boost/filesystem.hpp>
+
+#include <QUndoStack>
+
+#include "document.hpp"
+#include "savingstate.hpp"
+
+CSMDoc::OpenSaveStage::OpenSaveStage (Document& document, SavingState& state, bool projectFile)
+: mDocument (document), mState (state), mProjectFile (projectFile)
+{}
+
+int CSMDoc::OpenSaveStage::setup()
+{
+ return 1;
+}
+
+void CSMDoc::OpenSaveStage::perform (int stage, std::vector<std::string>& messages)
+{
+ mState.start (mDocument, mProjectFile);
+
+ mState.getStream().open ((mProjectFile ? mState.getPath() : mState.getTmpPath()).string().c_str());
+
+ if (!mState.getStream().is_open())
+ throw std::runtime_error ("failed to open stream for saving");
+}
+
+
+CSMDoc::WriteHeaderStage::WriteHeaderStage (Document& document, SavingState& state, bool simple)
+: mDocument (document), mState (state), mSimple (simple)
+{}
+
+int CSMDoc::WriteHeaderStage::setup()
+{
+ return 1;
+}
+
+void CSMDoc::WriteHeaderStage::perform (int stage, std::vector<std::string>& messages)
+{
+ mState.getWriter().setVersion();
+
+ mState.getWriter().clearMaster();
+
+ mState.getWriter().setFormat (0);
+
+ if (mSimple)
+ {
+ mState.getWriter().setAuthor ("");
+ mState.getWriter().setDescription ("");
+ mState.getWriter().setRecordCount (0);
+ }
+ else
+ {
+ mState.getWriter().setAuthor (mDocument.getData().getAuthor());
+ mState.getWriter().setDescription (mDocument.getData().getDescription());
+ mState.getWriter().setRecordCount (
+ mDocument.getData().count (CSMWorld::RecordBase::State_Modified) +
+ mDocument.getData().count (CSMWorld::RecordBase::State_ModifiedOnly) +
+ mDocument.getData().count (CSMWorld::RecordBase::State_Deleted));
+
+ /// \todo refine dependency list (at least remove redundant dependencies)
+ std::vector<boost::filesystem::path> dependencies = mDocument.getContentFiles();
+ std::vector<boost::filesystem::path>::const_iterator end (--dependencies.end());
+
+ for (std::vector<boost::filesystem::path>::const_iterator iter (dependencies.begin());
+ iter!=end; ++iter)
+ {
+ std::string name = iter->filename().string();
+ uint64_t size = boost::filesystem::file_size (*iter);
+
+ mState.getWriter().addMaster (name, size);
+ }
+ }
+
+ mState.getWriter().save (mState.getStream());
+}
+
+
+CSMDoc::WriteRefIdCollectionStage::WriteRefIdCollectionStage (Document& document, SavingState& state)
+: mDocument (document), mState (state)
+{}
+
+int CSMDoc::WriteRefIdCollectionStage::setup()
+{
+ return mDocument.getData().getReferenceables().getSize();
+}
+
+void CSMDoc::WriteRefIdCollectionStage::perform (int stage, std::vector<std::string>& messages)
+{
+ mDocument.getData().getReferenceables().save (stage, mState.getWriter());
+}
+
+
+CSMDoc::WriteFilterStage::WriteFilterStage (Document& document, SavingState& state,
+ CSMFilter::Filter::Scope scope)
+: WriteCollectionStage<CSMWorld::IdCollection<CSMFilter::Filter> > (document.getData().getFilters(),
+ state),
+ mDocument (document), mScope (scope)
+{}
+
+void CSMDoc::WriteFilterStage::perform (int stage, std::vector<std::string>& messages)
+{
+ const CSMWorld::Record<CSMFilter::Filter>& record =
+ mDocument.getData().getFilters().getRecord (stage);
+
+ if (record.get().mScope==mScope)
+ WriteCollectionStage<CSMWorld::IdCollection<CSMFilter::Filter> >::perform (stage, messages);
+}
+
+
+CSMDoc::CloseSaveStage::CloseSaveStage (SavingState& state)
+: mState (state)
+{}
+
+int CSMDoc::CloseSaveStage::setup()
+{
+ return 1;
+}
+
+void CSMDoc::CloseSaveStage::perform (int stage, std::vector<std::string>& messages)
+{
+ mState.getStream().close();
+
+ if (!mState.getStream())
+ throw std::runtime_error ("saving failed");
+}
+
+
+CSMDoc::FinalSavingStage::FinalSavingStage (Document& document, SavingState& state)
+: mDocument (document), mState (state)
+{}
+
+int CSMDoc::FinalSavingStage::setup()
+{
+ return 1;
+}
+
+void CSMDoc::FinalSavingStage::perform (int stage, std::vector<std::string>& messages)
+{
+ if (mState.hasError())
+ {
+ mState.getWriter().close();
+ mState.getStream().close();
+
+ if (boost::filesystem::exists (mState.getTmpPath()))
+ boost::filesystem::remove (mState.getTmpPath());
+ }
+ else if (!mState.isProjectFile())
+ {
+ if (boost::filesystem::exists (mState.getPath()))
+ boost::filesystem::remove (mState.getPath());
+
+ boost::filesystem::rename (mState.getTmpPath(), mState.getPath());
+
+ mDocument.getUndoStack().setClean();
+ }
+} \ No newline at end of file
diff --git a/apps/opencs/model/doc/savingstages.hpp b/apps/opencs/model/doc/savingstages.hpp
new file mode 100644
index 0000000000..ff94116fdb
--- /dev/null
+++ b/apps/opencs/model/doc/savingstages.hpp
@@ -0,0 +1,172 @@
+#ifndef CSM_DOC_SAVINGSTAGES_H
+#define CSM_DOC_SAVINGSTAGES_H
+
+#include "stage.hpp"
+
+#include "savingstate.hpp"
+
+#include "../world/record.hpp"
+#include "../world/idcollection.hpp"
+
+#include "../filter/filter.hpp"
+
+namespace CSMDoc
+{
+ class Document;
+ class SavingState;
+
+ class OpenSaveStage : public Stage
+ {
+ Document& mDocument;
+ SavingState& mState;
+ bool mProjectFile;
+
+ public:
+
+ OpenSaveStage (Document& document, SavingState& state, bool projectFile);
+ ///< \param projectFile Saving the project file instead of the content file.
+
+ virtual int setup();
+ ///< \return number of steps
+
+ virtual void perform (int stage, std::vector<std::string>& messages);
+ ///< Messages resulting from this stage will be appended to \a messages.
+ };
+
+ class WriteHeaderStage : public Stage
+ {
+ Document& mDocument;
+ SavingState& mState;
+ bool mSimple;
+
+ public:
+
+ WriteHeaderStage (Document& document, SavingState& state, bool simple);
+ ///< \param simple Simplified header (used for project files).
+
+ virtual int setup();
+ ///< \return number of steps
+
+ virtual void perform (int stage, std::vector<std::string>& messages);
+ ///< Messages resulting from this stage will be appended to \a messages.
+ };
+
+
+ template<class CollectionT>
+ class WriteCollectionStage : public Stage
+ {
+ const CollectionT& mCollection;
+ SavingState& mState;
+
+ public:
+
+ WriteCollectionStage (const CollectionT& collection, SavingState& state);
+
+ virtual int setup();
+ ///< \return number of steps
+
+ virtual void perform (int stage, std::vector<std::string>& messages);
+ ///< Messages resulting from this stage will be appended to \a messages.
+ };
+
+ template<class CollectionT>
+ WriteCollectionStage<CollectionT>::WriteCollectionStage (const CollectionT& collection,
+ SavingState& state)
+ : mCollection (collection), mState (state)
+ {}
+
+ template<class CollectionT>
+ int WriteCollectionStage<CollectionT>::setup()
+ {
+ return mCollection.getSize();
+ }
+
+ template<class CollectionT>
+ void WriteCollectionStage<CollectionT>::perform (int stage, std::vector<std::string>& messages)
+ {
+ CSMWorld::RecordBase::State state = mCollection.getRecord (stage).mState;
+
+ if (state==CSMWorld::RecordBase::State_Modified ||
+ state==CSMWorld::RecordBase::State_ModifiedOnly)
+ {
+ std::string type;
+ for (int i=0; i<4; ++i)
+ /// \todo make endianess agnostic (change ESMWriter interface?)
+ type += reinterpret_cast<const char *> (&mCollection.getRecord (stage).mModified.sRecordId)[i];
+
+ mState.getWriter().startRecord (type);
+ mState.getWriter().writeHNCString ("NAME", mCollection.getId (stage));
+ mCollection.getRecord (stage).mModified.save (mState.getWriter());
+ mState.getWriter().endRecord (type);
+ }
+ else if (state==CSMWorld::RecordBase::State_Deleted)
+ {
+ /// \todo write record with delete flag
+ }
+ }
+
+
+ class WriteRefIdCollectionStage : public Stage
+ {
+ Document& mDocument;
+ SavingState& mState;
+
+ public:
+
+ WriteRefIdCollectionStage (Document& document, SavingState& state);
+
+ virtual int setup();
+ ///< \return number of steps
+
+ virtual void perform (int stage, std::vector<std::string>& messages);
+ ///< Messages resulting from this stage will be appended to \a messages.
+ };
+
+
+ class WriteFilterStage : public WriteCollectionStage<CSMWorld::IdCollection<CSMFilter::Filter> >
+ {
+ Document& mDocument;
+ CSMFilter::Filter::Scope mScope;
+
+ public:
+
+ WriteFilterStage (Document& document, SavingState& state, CSMFilter::Filter::Scope scope);
+
+ virtual void perform (int stage, std::vector<std::string>& messages);
+ ///< Messages resulting from this stage will be appended to \a messages.
+ };
+
+
+ class CloseSaveStage : public Stage
+ {
+ SavingState& mState;
+
+ public:
+
+ CloseSaveStage (SavingState& state);
+
+ virtual int setup();
+ ///< \return number of steps
+
+ virtual void perform (int stage, std::vector<std::string>& messages);
+ ///< Messages resulting from this stage will be appended to \a messages.
+ };
+
+ class FinalSavingStage : public Stage
+ {
+ Document& mDocument;
+ SavingState& mState;
+
+ public:
+
+ FinalSavingStage (Document& document, SavingState& state);
+
+ virtual int setup();
+ ///< \return number of steps
+
+ virtual void perform (int stage, std::vector<std::string>& messages);
+ ///< Messages resulting from this stage will be appended to \a messages.
+ };
+}
+
+#endif
diff --git a/apps/opencs/model/doc/savingstate.cpp b/apps/opencs/model/doc/savingstate.cpp
new file mode 100644
index 0000000000..4a1abb8883
--- /dev/null
+++ b/apps/opencs/model/doc/savingstate.cpp
@@ -0,0 +1,65 @@
+
+#include "savingstate.hpp"
+
+#include "operation.hpp"
+#include "document.hpp"
+
+CSMDoc::SavingState::SavingState (Operation& operation, const boost::filesystem::path& projectPath)
+: mOperation (operation),
+ /// \todo set encoding properly, once config implementation has been fixed.
+ mEncoder (ToUTF8::calculateEncoding ("win1252")),
+ mProjectPath (projectPath), mProjectFile (false)
+{
+ mWriter.setEncoder (&mEncoder);
+}
+
+bool CSMDoc::SavingState::hasError() const
+{
+ return mOperation.hasError();
+}
+
+void CSMDoc::SavingState::start (Document& document, bool project)
+{
+ mProjectFile = project;
+
+ if (mStream.is_open())
+ mStream.close();
+
+ mStream.clear();
+
+ if (project)
+ mPath = mProjectPath;
+ else
+ mPath = document.getSavePath();
+
+ boost::filesystem::path file (mPath.filename().string() + ".tmp");
+
+ mTmpPath = mPath.parent_path();
+
+ mTmpPath /= file;
+}
+
+const boost::filesystem::path& CSMDoc::SavingState::getPath() const
+{
+ return mPath;
+}
+
+const boost::filesystem::path& CSMDoc::SavingState::getTmpPath() const
+{
+ return mTmpPath;
+}
+
+std::ofstream& CSMDoc::SavingState::getStream()
+{
+ return mStream;
+}
+
+ESM::ESMWriter& CSMDoc::SavingState::getWriter()
+{
+ return mWriter;
+}
+
+bool CSMDoc::SavingState::isProjectFile() const
+{
+ return mProjectFile;
+} \ No newline at end of file
diff --git a/apps/opencs/model/doc/savingstate.hpp b/apps/opencs/model/doc/savingstate.hpp
new file mode 100644
index 0000000000..8cf7883e50
--- /dev/null
+++ b/apps/opencs/model/doc/savingstate.hpp
@@ -0,0 +1,50 @@
+#ifndef CSM_DOC_SAVINGSTATE_H
+#define CSM_DOC_SAVINGSTATE_H
+
+#include <fstream>
+
+#include <boost/filesystem/path.hpp>
+
+#include <components/esm/esmwriter.hpp>
+
+namespace CSMDoc
+{
+ class Operation;
+ class Document;
+
+ class SavingState
+ {
+ Operation& mOperation;
+ boost::filesystem::path mPath;
+ boost::filesystem::path mTmpPath;
+ ToUTF8::Utf8Encoder mEncoder;
+ std::ofstream mStream;
+ ESM::ESMWriter mWriter;
+ boost::filesystem::path mProjectPath;
+ bool mProjectFile;
+
+ public:
+
+ SavingState (Operation& operation, const boost::filesystem::path& projectPath);
+
+ bool hasError() const;
+
+ void start (Document& document, bool project);
+ ///< \param project Save project file instead of content file.
+
+ const boost::filesystem::path& getPath() const;
+
+ const boost::filesystem::path& getTmpPath() const;
+
+ std::ofstream& getStream();
+
+ ESM::ESMWriter& getWriter();
+
+ bool isProjectFile() const;
+ ///< Currently saving project file? (instead of content file)
+ };
+
+
+}
+
+#endif \ No newline at end of file
diff --git a/apps/opencs/model/doc/stage.cpp b/apps/opencs/model/doc/stage.cpp
new file mode 100644
index 0000000000..99b7657709
--- /dev/null
+++ b/apps/opencs/model/doc/stage.cpp
@@ -0,0 +1,4 @@
+
+#include "stage.hpp"
+
+CSMDoc::Stage::~Stage() {} \ No newline at end of file
diff --git a/apps/opencs/model/tools/stage.hpp b/apps/opencs/model/doc/stage.hpp
index 3020936f32..1f96c60b43 100644
--- a/apps/opencs/model/tools/stage.hpp
+++ b/apps/opencs/model/doc/stage.hpp
@@ -1,10 +1,10 @@
-#ifndef CSM_TOOLS_STAGE_H
-#define CSM_TOOLS_STAGE_H
+#ifndef CSM_DOC_STAGE_H
+#define CSM_DOC_STAGE_H
#include <vector>
#include <string>
-namespace CSMTools
+namespace CSMDoc
{
class Stage
{
@@ -16,7 +16,7 @@ namespace CSMTools
///< \return number of steps
virtual void perform (int stage, std::vector<std::string>& messages) = 0;
- ///< Messages resulting from this tage will be appended to \a messages.
+ ///< Messages resulting from this stage will be appended to \a messages.
};
}
diff --git a/apps/opencs/model/filter/parser.cpp b/apps/opencs/model/filter/parser.cpp
index d334a7f634..8f4fcb70c9 100644
--- a/apps/opencs/model/filter/parser.cpp
+++ b/apps/opencs/model/filter/parser.cpp
@@ -49,19 +49,31 @@ namespace CSMFilter
Token (Type type = Type_None);
+ Token (Type type, const std::string& string);
+ ///< Non-string type that can also be interpreted as a string.
+
Token (const std::string& string);
Token (double number);
operator bool() const;
+
+ bool isString() const;
};
Token::Token (Type type) : mType (type) {}
+ Token::Token (Type type, const std::string& string) : mType (type), mString (string) {}
+
Token::Token (const std::string& string) : mType (Type_String), mString (string) {}
Token::Token (double number) : mType (Type_Number), mNumber (number) {}
+ bool Token::isString() const
+ {
+ return mType==Type_String || mType>=Type_Keyword_True;
+ }
+
Token::operator bool() const
{
return mType!=Type_None;
@@ -120,7 +132,7 @@ CSMFilter::Token CSMFilter::Parser::getStringToken()
}
if (string[0]=='"')
- string = string.substr (1, string.size()-2);
+ return string.substr (1, string.size()-2);
}
return checkKeywords (string);
@@ -182,7 +194,7 @@ CSMFilter::Token CSMFilter::Parser::checkKeywords (const Token& token)
for (int i=0; sKeywords[i]; ++i)
if (sKeywords[i]==string || (string.size()==1 && sKeywords[i][0]==string[0]))
- return Token (static_cast<Token::Type> (i+Token::Type_Keyword_True));
+ return Token (static_cast<Token::Type> (i+Token::Type_Keyword_True), token.mString);
return token;
}
@@ -351,7 +363,7 @@ boost::shared_ptr<CSMFilter::Node> CSMFilter::Parser::parseText()
if (static_cast<int> (token.mNumber)==token.mNumber)
columnId = static_cast<int> (token.mNumber);
}
- else if (token.mType==Token::Type_String)
+ else if (token.isString())
{
columnId = CSMWorld::Columns::getId (token.mString);
}
@@ -373,7 +385,7 @@ boost::shared_ptr<CSMFilter::Node> CSMFilter::Parser::parseText()
// parse text pattern
token = getNextToken();
- if (token.mType!=Token::Type_String)
+ if (!token.isString())
{
error();
return boost::shared_ptr<Node>();
@@ -415,7 +427,7 @@ boost::shared_ptr<CSMFilter::Node> CSMFilter::Parser::parseValue()
if (static_cast<int> (token.mNumber)==token.mNumber)
columnId = static_cast<int> (token.mNumber);
}
- else if (token.mType==Token::Type_String)
+ else if (token.isString())
{
columnId = CSMWorld::Columns::getId (token.mString);
}
@@ -437,22 +449,22 @@ boost::shared_ptr<CSMFilter::Node> CSMFilter::Parser::parseValue()
// parse value
double lower = 0;
double upper = 0;
- bool min = false;
- bool max = false;
+ ValueNode::Type lowerType = ValueNode::Type_Open;
+ ValueNode::Type upperType = ValueNode::Type_Open;
token = getNextToken();
if (token.mType==Token::Type_Number)
{
// single value
- min = max = true;
lower = upper = token.mNumber;
+ lowerType = upperType = ValueNode::Type_Closed;
}
else
{
// interval
if (token.mType==Token::Type_OpenSquare)
- min = true;
+ lowerType = ValueNode::Type_Closed;
else if (token.mType!=Token::Type_CloseSquare && token.mType!=Token::Type_Open)
{
error();
@@ -461,17 +473,23 @@ boost::shared_ptr<CSMFilter::Node> CSMFilter::Parser::parseValue()
token = getNextToken();
- if (token.mType!=Token::Type_Number)
+ if (token.mType==Token::Type_Number)
{
- error();
- return boost::shared_ptr<Node>();
- }
+ lower = token.mNumber;
- lower = token.mNumber;
-
- token = getNextToken();
+ token = getNextToken();
- if (token.mType!=Token::Type_Comma)
+ if (token.mType!=Token::Type_Comma)
+ {
+ error();
+ return boost::shared_ptr<Node>();
+ }
+ }
+ else if (token.mType==Token::Type_Comma)
+ {
+ lowerType = ValueNode::Type_Infinite;
+ }
+ else
{
error();
return boost::shared_ptr<Node>();
@@ -479,18 +497,20 @@ boost::shared_ptr<CSMFilter::Node> CSMFilter::Parser::parseValue()
token = getNextToken();
- if (token.mType!=Token::Type_Number)
+ if (token.mType==Token::Type_Number)
{
- error();
- return boost::shared_ptr<Node>();
- }
+ upper = token.mNumber;
- upper = token.mNumber;
-
- token = getNextToken();
+ token = getNextToken();
+ }
+ else
+ upperType = ValueNode::Type_Infinite;
if (token.mType==Token::Type_CloseSquare)
- max = true;
+ {
+ if (upperType!=ValueNode::Type_Infinite)
+ upperType = ValueNode::Type_Closed;
+ }
else if (token.mType!=Token::Type_OpenSquare && token.mType!=Token::Type_Close)
{
error();
@@ -506,7 +526,7 @@ boost::shared_ptr<CSMFilter::Node> CSMFilter::Parser::parseValue()
return boost::shared_ptr<Node>();
}
- return boost::shared_ptr<Node> (new ValueNode (columnId, lower, upper, min, max));
+ return boost::shared_ptr<Node> (new ValueNode (columnId, lowerType, upperType, lower, upper));
}
void CSMFilter::Parser::error()
@@ -553,6 +573,8 @@ bool CSMFilter::Parser::parse (const std::string& filter, bool allowPredefined)
return true;
}
+ // We do not use isString() here, because there could be a pre-defined filter with an ID that is
+ // equal a filter keyword.
else if (token.mType==Token::Type_String && allowPredefined)
{
if (getNextToken()!=Token (Token::Type_EOS))
diff --git a/apps/opencs/model/filter/textnode.cpp b/apps/opencs/model/filter/textnode.cpp
index 9987c66d22..7d1a4845f6 100644
--- a/apps/opencs/model/filter/textnode.cpp
+++ b/apps/opencs/model/filter/textnode.cpp
@@ -28,13 +28,36 @@ bool CSMFilter::TextNode::test (const CSMWorld::IdTable& table, int row,
QVariant data = table.data (index);
- if (data.type()!=QVariant::String)
+ QString string;
+
+ if (data.type()==QVariant::String)
+ {
+ string = data.toString();
+ }
+ else if ((data.type()==QVariant::Int || data.type()==QVariant::UInt) &&
+ CSMWorld::Columns::hasEnums (static_cast<CSMWorld::Columns::ColumnId> (mColumnId)))
+ {
+ int value = data.toInt();
+
+ std::vector<std::string> enums =
+ CSMWorld::Columns::getEnums (static_cast<CSMWorld::Columns::ColumnId> (mColumnId));
+
+ if (value>=0 && value<static_cast<int> (enums.size()))
+ string = QString::fromUtf8 (enums[value].c_str());
+ }
+ else if (data.type()==QVariant::Bool)
+ {
+ string = data.toBool() ? "true" : "false";
+ }
+ else if (mText.empty() && !data.isValid())
+ return true;
+ else
return false;
/// \todo make pattern syntax configurable
QRegExp regExp (QString::fromUtf8 (mText.c_str()), Qt::CaseInsensitive);
- return regExp.exactMatch (data.toString());
+ return regExp.exactMatch (string);
}
std::vector<int> CSMFilter::TextNode::getReferencedColumns() const
diff --git a/apps/opencs/model/filter/valuenode.cpp b/apps/opencs/model/filter/valuenode.cpp
index f6cb20e4cb..fdcce00ab3 100644
--- a/apps/opencs/model/filter/valuenode.cpp
+++ b/apps/opencs/model/filter/valuenode.cpp
@@ -7,10 +7,9 @@
#include "../world/columns.hpp"
#include "../world/idtable.hpp"
-CSMFilter::ValueNode::ValueNode (int columnId,
- double lower, double upper, bool min, bool max)
-: mColumnId (columnId), mLower (lower), mUpper (upper), mMin (min), mMax (max)
-{}
+CSMFilter::ValueNode::ValueNode (int columnId, Type lowerType, Type upperType,
+ double lower, double upper)
+: mColumnId (columnId), mLowerType (lowerType), mUpperType (upperType), mLower (lower), mUpper (upper){}
bool CSMFilter::ValueNode::test (const CSMWorld::IdTable& table, int row,
const std::map<int, int>& columns) const
@@ -18,7 +17,7 @@ bool CSMFilter::ValueNode::test (const CSMWorld::IdTable& table, int row,
const std::map<int, int>::const_iterator iter = columns.find (mColumnId);
if (iter==columns.end())
- throw std::logic_error ("invalid column in test value test");
+ throw std::logic_error ("invalid column in value node test");
if (iter->second==-1)
return true;
@@ -28,15 +27,26 @@ bool CSMFilter::ValueNode::test (const CSMWorld::IdTable& table, int row,
QVariant data = table.data (index);
if (data.type()!=QVariant::Double && data.type()!=QVariant::Bool && data.type()!=QVariant::Int &&
- data.type()!=QVariant::UInt)
+ data.type()!=QVariant::UInt && data.type()!=static_cast<QVariant::Type> (QMetaType::Float))
return false;
double value = data.toDouble();
- if (mLower==mUpper && mMin && mMax)
- return value==mLower;
-
- return (mMin ? value>=mLower : value>mLower) && (mMax ? value<=mUpper : value<mUpper);
+ switch (mLowerType)
+ {
+ case Type_Closed: if (value<mLower) return false; break;
+ case Type_Open: if (value<=mLower) return false; break;
+ case Type_Infinite: break;
+ }
+
+ switch (mUpperType)
+ {
+ case Type_Closed: if (value>mUpper) return false; break;
+ case Type_Open: if (value>=mUpper) return false; break;
+ case Type_Infinite: break;
+ }
+
+ return true;
}
std::vector<int> CSMFilter::ValueNode::getReferencedColumns() const
@@ -58,12 +68,28 @@ std::string CSMFilter::ValueNode::toString (bool numericColumns) const
<< CSMWorld::Columns::getName (static_cast<CSMWorld::Columns::ColumnId> (mColumnId))
<< "\"";
- stream << ", \"";
+ stream << ", ";
- if (mLower==mUpper && mMin && mMax)
+ if (mLower==mUpper && mLowerType!=Type_Infinite && mUpperType!=Type_Infinite)
stream << mLower;
else
- stream << (mMin ? "[" : "(") << mLower << ", " << mUpper << (mMax ? "]" : ")");
+ {
+ switch (mLowerType)
+ {
+ case Type_Closed: stream << "[" << mLower; break;
+ case Type_Open: stream << "(" << mLower; break;
+ case Type_Infinite: stream << "("; break;
+ }
+
+ stream << ", ";
+
+ switch (mUpperType)
+ {
+ case Type_Closed: stream << mUpper << "]"; break;
+ case Type_Open: stream << mUpper << ")"; break;
+ case Type_Infinite: stream << ")"; break;
+ }
+ }
stream << ")";
diff --git a/apps/opencs/model/filter/valuenode.hpp b/apps/opencs/model/filter/valuenode.hpp
index faaa1e2ff6..b1050709d0 100644
--- a/apps/opencs/model/filter/valuenode.hpp
+++ b/apps/opencs/model/filter/valuenode.hpp
@@ -7,16 +7,25 @@ namespace CSMFilter
{
class ValueNode : public LeafNode
{
+ public:
+
+ enum Type
+ {
+ Type_Closed, Type_Open, Type_Infinite
+ };
+
+ private:
+
int mColumnId;
std::string mText;
double mLower;
double mUpper;
- bool mMin;
- bool mMax;
+ Type mLowerType;
+ Type mUpperType;
public:
- ValueNode (int columnId, double lower, double upper, bool min, bool max);
+ ValueNode (int columnId, Type lowerType, Type upperType, double lower, double upper);
virtual bool test (const CSMWorld::IdTable& table, int row,
const std::map<int, int>& columns) const;
diff --git a/apps/opencs/model/tools/birthsigncheck.cpp b/apps/opencs/model/tools/birthsigncheck.cpp
index b673c93ded..59c65086ed 100644
--- a/apps/opencs/model/tools/birthsigncheck.cpp
+++ b/apps/opencs/model/tools/birthsigncheck.cpp
@@ -19,7 +19,12 @@ int CSMTools::BirthsignCheckStage::setup()
void CSMTools::BirthsignCheckStage::perform (int stage, std::vector<std::string>& messages)
{
- const ESM::BirthSign& birthsign = mBirthsigns.getRecord (stage).get();
+ const CSMWorld::Record<ESM::BirthSign>& record = mBirthsigns.getRecord (stage);
+
+ if (record.isDeleted())
+ return;
+
+ const ESM::BirthSign& birthsign = record.get();
CSMWorld::UniversalId id (CSMWorld::UniversalId::Type_Birthsign, birthsign.mId);
diff --git a/apps/opencs/model/tools/birthsigncheck.hpp b/apps/opencs/model/tools/birthsigncheck.hpp
index 42b5a6b244..bdd65b44ab 100644
--- a/apps/opencs/model/tools/birthsigncheck.hpp
+++ b/apps/opencs/model/tools/birthsigncheck.hpp
@@ -5,12 +5,12 @@
#include "../world/idcollection.hpp"
-#include "stage.hpp"
+#include "../doc/stage.hpp"
namespace CSMTools
{
/// \brief VerifyStage: make sure that birthsign records are internally consistent
- class BirthsignCheckStage : public Stage
+ class BirthsignCheckStage : public CSMDoc::Stage
{
const CSMWorld::IdCollection<ESM::BirthSign>& mBirthsigns;
diff --git a/apps/opencs/model/tools/classcheck.cpp b/apps/opencs/model/tools/classcheck.cpp
index da2e9f19a6..6923b31535 100644
--- a/apps/opencs/model/tools/classcheck.cpp
+++ b/apps/opencs/model/tools/classcheck.cpp
@@ -20,7 +20,12 @@ int CSMTools::ClassCheckStage::setup()
void CSMTools::ClassCheckStage::perform (int stage, std::vector<std::string>& messages)
{
- const ESM::Class& class_= mClasses.getRecord (stage).get();
+ const CSMWorld::Record<ESM::Class>& record = mClasses.getRecord (stage);
+
+ if (record.isDeleted())
+ return;
+
+ const ESM::Class& class_ = record.get();
CSMWorld::UniversalId id (CSMWorld::UniversalId::Type_Class, class_.mId);
diff --git a/apps/opencs/model/tools/classcheck.hpp b/apps/opencs/model/tools/classcheck.hpp
index a29d7c8b78..3604b451c5 100644
--- a/apps/opencs/model/tools/classcheck.hpp
+++ b/apps/opencs/model/tools/classcheck.hpp
@@ -5,12 +5,12 @@
#include "../world/idcollection.hpp"
-#include "stage.hpp"
+#include "../doc/stage.hpp"
namespace CSMTools
{
/// \brief VerifyStage: make sure that class records are internally consistent
- class ClassCheckStage : public Stage
+ class ClassCheckStage : public CSMDoc::Stage
{
const CSMWorld::IdCollection<ESM::Class>& mClasses;
diff --git a/apps/opencs/model/tools/factioncheck.cpp b/apps/opencs/model/tools/factioncheck.cpp
index af26904efa..c219e56102 100644
--- a/apps/opencs/model/tools/factioncheck.cpp
+++ b/apps/opencs/model/tools/factioncheck.cpp
@@ -20,7 +20,12 @@ int CSMTools::FactionCheckStage::setup()
void CSMTools::FactionCheckStage::perform (int stage, std::vector<std::string>& messages)
{
- const ESM::Faction& faction = mFactions.getRecord (stage).get();
+ const CSMWorld::Record<ESM::Faction>& record = mFactions.getRecord (stage);
+
+ if (record.isDeleted())
+ return;
+
+ const ESM::Faction& faction = record.get();
CSMWorld::UniversalId id (CSMWorld::UniversalId::Type_Faction, faction.mId);
diff --git a/apps/opencs/model/tools/factioncheck.hpp b/apps/opencs/model/tools/factioncheck.hpp
index 8686505727..7cd80347db 100644
--- a/apps/opencs/model/tools/factioncheck.hpp
+++ b/apps/opencs/model/tools/factioncheck.hpp
@@ -5,12 +5,12 @@
#include "../world/idcollection.hpp"
-#include "stage.hpp"
+#include "../doc/stage.hpp"
namespace CSMTools
{
/// \brief VerifyStage: make sure that faction records are internally consistent
- class FactionCheckStage : public Stage
+ class FactionCheckStage : public CSMDoc::Stage
{
const CSMWorld::IdCollection<ESM::Faction>& mFactions;
diff --git a/apps/opencs/model/tools/mandatoryid.hpp b/apps/opencs/model/tools/mandatoryid.hpp
index 342e2d7540..5fddf08d32 100644
--- a/apps/opencs/model/tools/mandatoryid.hpp
+++ b/apps/opencs/model/tools/mandatoryid.hpp
@@ -6,7 +6,7 @@
#include "../world/universalid.hpp"
-#include "stage.hpp"
+#include "../doc/stage.hpp"
namespace CSMWorld
{
@@ -16,7 +16,7 @@ namespace CSMWorld
namespace CSMTools
{
/// \brief Verify stage: make sure that records with specific IDs exist.
- class MandatoryIdStage : public Stage
+ class MandatoryIdStage : public CSMDoc::Stage
{
const CSMWorld::CollectionBase& mIdCollection;
CSMWorld::UniversalId mCollectionId;
diff --git a/apps/opencs/model/tools/racecheck.cpp b/apps/opencs/model/tools/racecheck.cpp
index 1e7a4cab45..413de5ef01 100644
--- a/apps/opencs/model/tools/racecheck.cpp
+++ b/apps/opencs/model/tools/racecheck.cpp
@@ -9,7 +9,12 @@
void CSMTools::RaceCheckStage::performPerRecord (int stage, std::vector<std::string>& messages)
{
- const ESM::Race& race = mRaces.getRecord (stage).get();
+ const CSMWorld::Record<ESM::Race>& record = mRaces.getRecord (stage);
+
+ if (record.isDeleted())
+ return;
+
+ const ESM::Race& race = record.get();
CSMWorld::UniversalId id (CSMWorld::UniversalId::Type_Race, race.mId);
diff --git a/apps/opencs/model/tools/racecheck.hpp b/apps/opencs/model/tools/racecheck.hpp
index 155f799021..ff9948bf6d 100644
--- a/apps/opencs/model/tools/racecheck.hpp
+++ b/apps/opencs/model/tools/racecheck.hpp
@@ -5,12 +5,12 @@
#include "../world/idcollection.hpp"
-#include "stage.hpp"
+#include "../doc/stage.hpp"
namespace CSMTools
{
/// \brief VerifyStage: make sure that race records are internally consistent
- class RaceCheckStage : public Stage
+ class RaceCheckStage : public CSMDoc::Stage
{
const CSMWorld::IdCollection<ESM::Race>& mRaces;
bool mPlayable;
diff --git a/apps/opencs/model/tools/regioncheck.cpp b/apps/opencs/model/tools/regioncheck.cpp
index ac64ac0271..4398e00ef6 100644
--- a/apps/opencs/model/tools/regioncheck.cpp
+++ b/apps/opencs/model/tools/regioncheck.cpp
@@ -19,7 +19,12 @@ int CSMTools::RegionCheckStage::setup()
void CSMTools::RegionCheckStage::perform (int stage, std::vector<std::string>& messages)
{
- const ESM::Region& region = mRegions.getRecord (stage).get();
+ const CSMWorld::Record<ESM::Region>& record = mRegions.getRecord (stage);
+
+ if (record.isDeleted())
+ return;
+
+ const ESM::Region& region = record.get();
CSMWorld::UniversalId id (CSMWorld::UniversalId::Type_Region, region.mId);
diff --git a/apps/opencs/model/tools/regioncheck.hpp b/apps/opencs/model/tools/regioncheck.hpp
index b421356514..c8c437cbd2 100644
--- a/apps/opencs/model/tools/regioncheck.hpp
+++ b/apps/opencs/model/tools/regioncheck.hpp
@@ -5,12 +5,12 @@
#include "../world/idcollection.hpp"
-#include "stage.hpp"
+#include "../doc/stage.hpp"
namespace CSMTools
{
/// \brief VerifyStage: make sure that region records are internally consistent
- class RegionCheckStage : public Stage
+ class RegionCheckStage : public CSMDoc::Stage
{
const CSMWorld::IdCollection<ESM::Region>& mRegions;
diff --git a/apps/opencs/model/tools/skillcheck.cpp b/apps/opencs/model/tools/skillcheck.cpp
index 897aeab473..28fc24fd39 100644
--- a/apps/opencs/model/tools/skillcheck.cpp
+++ b/apps/opencs/model/tools/skillcheck.cpp
@@ -18,7 +18,12 @@ int CSMTools::SkillCheckStage::setup()
void CSMTools::SkillCheckStage::perform (int stage, std::vector<std::string>& messages)
{
- const ESM::Skill& skill = mSkills.getRecord (stage).get();
+ const CSMWorld::Record<ESM::Skill>& record = mSkills.getRecord (stage);
+
+ if (record.isDeleted())
+ return;
+
+ const ESM::Skill& skill = record.get();
CSMWorld::UniversalId id (CSMWorld::UniversalId::Type_Skill, skill.mId);
diff --git a/apps/opencs/model/tools/skillcheck.hpp b/apps/opencs/model/tools/skillcheck.hpp
index 30a3f01cad..662bdadee1 100644
--- a/apps/opencs/model/tools/skillcheck.hpp
+++ b/apps/opencs/model/tools/skillcheck.hpp
@@ -5,12 +5,12 @@
#include "../world/idcollection.hpp"
-#include "stage.hpp"
+#include "../doc/stage.hpp"
namespace CSMTools
{
/// \brief VerifyStage: make sure that skill records are internally consistent
- class SkillCheckStage : public Stage
+ class SkillCheckStage : public CSMDoc::Stage
{
const CSMWorld::IdCollection<ESM::Skill>& mSkills;
diff --git a/apps/opencs/model/tools/soundcheck.cpp b/apps/opencs/model/tools/soundcheck.cpp
index 52834e6594..dce2d2b6fa 100644
--- a/apps/opencs/model/tools/soundcheck.cpp
+++ b/apps/opencs/model/tools/soundcheck.cpp
@@ -18,7 +18,12 @@ int CSMTools::SoundCheckStage::setup()
void CSMTools::SoundCheckStage::perform (int stage, std::vector<std::string>& messages)
{
- const ESM::Sound& sound = mSounds.getRecord (stage).get();
+ const CSMWorld::Record<ESM::Sound>& record = mSounds.getRecord (stage);
+
+ if (record.isDeleted())
+ return;
+
+ const ESM::Sound& sound = record.get();
CSMWorld::UniversalId id (CSMWorld::UniversalId::Type_Sound, sound.mId);
diff --git a/apps/opencs/model/tools/soundcheck.hpp b/apps/opencs/model/tools/soundcheck.hpp
index a309763a12..00b45cd935 100644
--- a/apps/opencs/model/tools/soundcheck.hpp
+++ b/apps/opencs/model/tools/soundcheck.hpp
@@ -5,12 +5,12 @@
#include "../world/idcollection.hpp"
-#include "stage.hpp"
+#include "../doc/stage.hpp"
namespace CSMTools
{
/// \brief VerifyStage: make sure that sound records are internally consistent
- class SoundCheckStage : public Stage
+ class SoundCheckStage : public CSMDoc::Stage
{
const CSMWorld::IdCollection<ESM::Sound>& mSounds;
diff --git a/apps/opencs/model/tools/spellcheck.cpp b/apps/opencs/model/tools/spellcheck.cpp
index 3adee0a4ef..a2cc7c8d25 100644
--- a/apps/opencs/model/tools/spellcheck.cpp
+++ b/apps/opencs/model/tools/spellcheck.cpp
@@ -19,7 +19,12 @@ int CSMTools::SpellCheckStage::setup()
void CSMTools::SpellCheckStage::perform (int stage, std::vector<std::string>& messages)
{
- const ESM::Spell& spell = mSpells.getRecord (stage).get();
+ const CSMWorld::Record<ESM::Spell>& record = mSpells.getRecord (stage);
+
+ if (record.isDeleted())
+ return;
+
+ const ESM::Spell& spell = record.get();
CSMWorld::UniversalId id (CSMWorld::UniversalId::Type_Spell, spell.mId);
diff --git a/apps/opencs/model/tools/spellcheck.hpp b/apps/opencs/model/tools/spellcheck.hpp
index 0566392193..880ddafcd2 100644
--- a/apps/opencs/model/tools/spellcheck.hpp
+++ b/apps/opencs/model/tools/spellcheck.hpp
@@ -5,12 +5,12 @@
#include "../world/idcollection.hpp"
-#include "stage.hpp"
+#include "../doc/stage.hpp"
namespace CSMTools
{
/// \brief VerifyStage: make sure that spell records are internally consistent
- class SpellCheckStage : public Stage
+ class SpellCheckStage : public CSMDoc::Stage
{
const CSMWorld::IdCollection<ESM::Spell>& mSpells;
diff --git a/apps/opencs/model/tools/stage.cpp b/apps/opencs/model/tools/stage.cpp
deleted file mode 100644
index 6f4567e579..0000000000
--- a/apps/opencs/model/tools/stage.cpp
+++ /dev/null
@@ -1,4 +0,0 @@
-
-#include "stage.hpp"
-
-CSMTools::Stage::~Stage() {} \ No newline at end of file
diff --git a/apps/opencs/model/tools/tools.cpp b/apps/opencs/model/tools/tools.cpp
index 803861203c..cd4653280e 100644
--- a/apps/opencs/model/tools/tools.cpp
+++ b/apps/opencs/model/tools/tools.cpp
@@ -3,9 +3,8 @@
#include <QThreadPool>
-#include "verifier.hpp"
-
#include "../doc/state.hpp"
+#include "../doc/operation.hpp"
#include "../world/data.hpp"
#include "../world/universalid.hpp"
@@ -21,7 +20,7 @@
#include "birthsigncheck.hpp"
#include "spellcheck.hpp"
-CSMTools::Operation *CSMTools::Tools::get (int type)
+CSMDoc::Operation *CSMTools::Tools::get (int type)
{
switch (type)
{
@@ -31,19 +30,19 @@ CSMTools::Operation *CSMTools::Tools::get (int type)
return 0;
}
-const CSMTools::Operation *CSMTools::Tools::get (int type) const
+const CSMDoc::Operation *CSMTools::Tools::get (int type) const
{
return const_cast<Tools *> (this)->get (type);
}
-CSMTools::Verifier *CSMTools::Tools::getVerifier()
+CSMDoc::Operation *CSMTools::Tools::getVerifier()
{
if (!mVerifier)
{
- mVerifier = new Verifier;
+ mVerifier = new CSMDoc::Operation (CSMDoc::State_Verifying, false);
connect (mVerifier, SIGNAL (progress (int, int, int)), this, SIGNAL (progress (int, int, int)));
- connect (mVerifier, SIGNAL (finished()), this, SLOT (verifierDone()));
+ connect (mVerifier, SIGNAL (done (int)), this, SIGNAL (done (int)));
connect (mVerifier, SIGNAL (reportMessage (const QString&, int)),
this, SLOT (verifierMessage (const QString&, int)));
@@ -103,7 +102,7 @@ CSMWorld::UniversalId CSMTools::Tools::runVerifier()
void CSMTools::Tools::abortOperation (int type)
{
- if (Operation *operation = get (type))
+ if (CSMDoc::Operation *operation = get (type))
operation->abort();
}
@@ -118,7 +117,7 @@ int CSMTools::Tools::getRunningOperations() const
int result = 0;
for (int i=0; sOperations[i]!=-1; ++i)
- if (const Operation *operation = get (sOperations[i]))
+ if (const CSMDoc::Operation *operation = get (sOperations[i]))
if (operation->isRunning())
result |= sOperations[i];
@@ -133,11 +132,6 @@ CSMTools::ReportModel *CSMTools::Tools::getReport (const CSMWorld::UniversalId&
return mReports.at (id.getIndex());
}
-void CSMTools::Tools::verifierDone()
-{
- emit done (CSMDoc::State_Verifying);
-}
-
void CSMTools::Tools::verifierMessage (const QString& message, int type)
{
std::map<int, int>::iterator iter = mActiveReports.find (type);
diff --git a/apps/opencs/model/tools/tools.hpp b/apps/opencs/model/tools/tools.hpp
index 652345c6da..0079fab34e 100644
--- a/apps/opencs/model/tools/tools.hpp
+++ b/apps/opencs/model/tools/tools.hpp
@@ -11,10 +11,13 @@ namespace CSMWorld
class UniversalId;
}
-namespace CSMTools
+namespace CSMDoc
{
- class Verifier;
class Operation;
+}
+
+namespace CSMTools
+{
class ReportModel;
class Tools : public QObject
@@ -22,7 +25,7 @@ namespace CSMTools
Q_OBJECT
CSMWorld::Data& mData;
- Verifier *mVerifier;
+ CSMDoc::Operation *mVerifier;
std::map<int, ReportModel *> mReports;
int mNextReportNumber;
std::map<int, int> mActiveReports; // type, report number
@@ -31,12 +34,12 @@ namespace CSMTools
Tools (const Tools&);
Tools& operator= (const Tools&);
- Verifier *getVerifier();
+ CSMDoc::Operation *getVerifier();
- Operation *get (int type);
+ CSMDoc::Operation *get (int type);
///< Returns a 0-pointer, if operation hasn't been used yet.
- const Operation *get (int type) const;
+ const CSMDoc::Operation *get (int type) const;
///< Returns a 0-pointer, if operation hasn't been used yet.
public:
@@ -58,8 +61,6 @@ namespace CSMTools
private slots:
- void verifierDone();
-
void verifierMessage (const QString& message, int type);
signals:
diff --git a/apps/opencs/model/tools/verifier.cpp b/apps/opencs/model/tools/verifier.cpp
deleted file mode 100644
index 9c00d4ea7e..0000000000
--- a/apps/opencs/model/tools/verifier.cpp
+++ /dev/null
@@ -1,7 +0,0 @@
-
-#include "verifier.hpp"
-
-#include "../doc/state.hpp"
-
-CSMTools::Verifier::Verifier() : Operation (CSMDoc::State_Verifying)
-{}
diff --git a/apps/opencs/model/tools/verifier.hpp b/apps/opencs/model/tools/verifier.hpp
deleted file mode 100644
index 054f87169c..0000000000
--- a/apps/opencs/model/tools/verifier.hpp
+++ /dev/null
@@ -1,17 +0,0 @@
-#ifndef CSM_TOOLS_VERIFIER_H
-#define CSM_TOOLS_VERIFIER_H
-
-#include "operation.hpp"
-
-namespace CSMTools
-{
- class Verifier : public Operation
- {
- public:
-
- Verifier();
-
- };
-}
-
-#endif
diff --git a/apps/opencs/model/world/collection.hpp b/apps/opencs/model/world/collection.hpp
index 6cf31d0a4f..84a00cef82 100644
--- a/apps/opencs/model/world/collection.hpp
+++ b/apps/opencs/model/world/collection.hpp
@@ -107,6 +107,11 @@ namespace CSMWorld
virtual int getAppendIndex (UniversalId::Type type = UniversalId::Type_None) const;
///< \param type Will be ignored, unless the collection supports multiple record types
+ virtual std::vector<std::string> getIds (bool listDeleted = true) const;
+ ///< Return a sorted collection of all IDs
+ ///
+ /// \param listDeleted include deleted record in the list
+
void addColumn (Column<ESXRecordT> *column);
void setRecord (int index, const Record<ESXRecordT>& record);
@@ -294,6 +299,21 @@ namespace CSMWorld
}
template<typename ESXRecordT, typename IdAccessorT>
+ std::vector<std::string> Collection<ESXRecordT, IdAccessorT>::getIds (bool listDeleted) const
+ {
+ std::vector<std::string> ids;
+
+ for (typename std::map<std::string, int>::const_iterator iter = mIndex.begin();
+ iter!=mIndex.end(); ++iter)
+ {
+ if (listDeleted || !mRecords[iter->second].isDeleted())
+ ids.push_back (IdAccessorT().getId (mRecords[iter->second].get()));
+ }
+
+ return ids;
+ }
+
+ template<typename ESXRecordT, typename IdAccessorT>
const Record<ESXRecordT>& Collection<ESXRecordT, IdAccessorT>::getRecord (const std::string& id) const
{
int index = getIndex (id);
diff --git a/apps/opencs/model/world/collectionbase.cpp b/apps/opencs/model/world/collectionbase.cpp
index 932ea27b58..241f198cb2 100644
--- a/apps/opencs/model/world/collectionbase.cpp
+++ b/apps/opencs/model/world/collectionbase.cpp
@@ -1,6 +1,31 @@
#include "collectionbase.hpp"
+#include <stdexcept>
+
+#include "columnbase.hpp"
+
CSMWorld::CollectionBase::CollectionBase() {}
CSMWorld::CollectionBase::~CollectionBase() {}
+
+int CSMWorld::CollectionBase::searchColumnIndex (Columns::ColumnId id) const
+{
+ int columns = getColumns();
+
+ for (int i=0; i<columns; ++i)
+ if (getColumn (i).mColumnId==id)
+ return i;
+
+ return -1;
+}
+
+int CSMWorld::CollectionBase::findColumnIndex (Columns::ColumnId id) const
+{
+ int index = searchColumnIndex (id);
+
+ if (index==-1)
+ throw std::logic_error ("invalid column index");
+
+ return index;
+} \ No newline at end of file
diff --git a/apps/opencs/model/world/collectionbase.hpp b/apps/opencs/model/world/collectionbase.hpp
index 1700a68ecd..1056a961d5 100644
--- a/apps/opencs/model/world/collectionbase.hpp
+++ b/apps/opencs/model/world/collectionbase.hpp
@@ -4,6 +4,7 @@
#include <string>
#include "universalid.hpp"
+#include "columns.hpp"
class QVariant;
@@ -78,8 +79,19 @@ namespace CSMWorld
virtual int getAppendIndex (UniversalId::Type type = UniversalId::Type_None) const = 0;
///< \param type Will be ignored, unless the collection supports multiple record types
- };
+ virtual std::vector<std::string> getIds (bool listDeleted = true) const = 0;
+ ///< Return a sorted collection of all IDs
+ ///
+ /// \param listDeleted include deleted record in the list
+
+ int searchColumnIndex (Columns::ColumnId id) const;
+ ///< Return index of column with the given \a id. If no such column exists, -1 is returned.
+
+ int findColumnIndex (Columns::ColumnId id) const;
+ ///< Return index of column with the given \a id. If no such column exists, an exception is
+ /// thrown.
+ };
}
#endif \ No newline at end of file
diff --git a/apps/opencs/model/world/columnbase.hpp b/apps/opencs/model/world/columnbase.hpp
index c1b423c94c..9b8d7dafb8 100644
--- a/apps/opencs/model/world/columnbase.hpp
+++ b/apps/opencs/model/world/columnbase.hpp
@@ -43,7 +43,8 @@ namespace CSMWorld
Display_CreatureType,
Display_WeaponType,
Display_RecordState,
- Display_RefRecordType
+ Display_RefRecordType,
+ Display_DialogueType
};
int mColumnId;
diff --git a/apps/opencs/model/world/columnimp.hpp b/apps/opencs/model/world/columnimp.hpp
index 1a2bf9df13..8575480fd4 100644
--- a/apps/opencs/model/world/columnimp.hpp
+++ b/apps/opencs/model/world/columnimp.hpp
@@ -1216,6 +1216,138 @@ namespace CSMWorld
return true;
}
};
+
+ template<typename ESXRecordT>
+ struct ScopeColumn : public Column<ESXRecordT>
+ {
+ ScopeColumn()
+ : Column<ESXRecordT> (Columns::ColumnId_Scope, ColumnBase::Display_Integer, 0)
+ {}
+
+ virtual QVariant get (const Record<ESXRecordT>& record) const
+ {
+ return static_cast<int> (record.get().mScope);
+ }
+
+ virtual void set (Record<ESXRecordT>& record, const QVariant& data)
+ {
+ ESXRecordT record2 = record.get();
+ record2.mScope = static_cast<CSMFilter::Filter::Scope> (data.toInt());
+ record.setModified (record2);
+ }
+
+ virtual bool isEditable() const
+ {
+ return true;
+ }
+
+ virtual bool isUserEditable() const
+ {
+ return false;
+ }
+ };
+
+
+ template<typename ESXRecordT>
+ struct PosColumn : public Column<ESXRecordT>
+ {
+ ESM::Position ESXRecordT::* mPosition;
+ int mIndex;
+
+ PosColumn (ESM::Position ESXRecordT::* position, int index, bool door)
+ : Column<ESXRecordT> (
+ (door ? Columns::ColumnId_DoorPositionXPos : Columns::ColumnId_PositionXPos)+index,
+ ColumnBase::Display_Float), mPosition (position), mIndex (index) {}
+
+ virtual QVariant get (const Record<ESXRecordT>& record) const
+ {
+ const ESM::Position& position = record.get().*mPosition;
+ return position.pos[mIndex];
+ }
+
+ virtual void set (Record<ESXRecordT>& record, const QVariant& data)
+ {
+ ESXRecordT record2 = record.get();
+
+ ESM::Position& position = record.get().*mPosition;
+
+ position.pos[mIndex] = data.toFloat();
+
+ record.setModified (record2);
+ }
+
+ virtual bool isEditable() const
+ {
+ return true;
+ }
+ };
+
+ template<typename ESXRecordT>
+ struct RotColumn : public Column<ESXRecordT>
+ {
+ ESM::Position ESXRecordT::* mPosition;
+ int mIndex;
+
+ RotColumn (ESM::Position ESXRecordT::* position, int index, bool door)
+ : Column<ESXRecordT> (
+ (door ? Columns::ColumnId_DoorPositionXRot : Columns::ColumnId_PositionXRot)+index,
+ ColumnBase::Display_Float), mPosition (position), mIndex (index) {}
+
+ virtual QVariant get (const Record<ESXRecordT>& record) const
+ {
+ const ESM::Position& position = record.get().*mPosition;
+ return position.rot[mIndex];
+ }
+
+ virtual void set (Record<ESXRecordT>& record, const QVariant& data)
+ {
+ ESXRecordT record2 = record.get();
+
+ ESM::Position& position = record.get().*mPosition;
+
+ position.rot[mIndex] = data.toFloat();
+
+ record.setModified (record2);
+ }
+
+ virtual bool isEditable() const
+ {
+ return true;
+ }
+ };
+
+ template<typename ESXRecordT>
+ struct DialogueTypeColumn : public Column<ESXRecordT>
+ {
+ DialogueTypeColumn (bool hidden = false)
+ : Column<ESXRecordT> (Columns::ColumnId_DialogueType, ColumnBase::Display_DialogueType,
+ hidden ? 0 : ColumnBase::Flag_Table | ColumnBase::Flag_Dialogue)
+ {}
+
+ virtual QVariant get (const Record<ESXRecordT>& record) const
+ {
+ return static_cast<int> (record.get().mType);
+ }
+
+ virtual void set (Record<ESXRecordT>& record, const QVariant& data)
+ {
+ ESXRecordT record2 = record.get();
+
+ record2.mType = data.toInt();
+
+ record.setModified (record2);
+ }
+
+ virtual bool isEditable() const
+ {
+ return true;
+ }
+
+ virtual bool isUserEditable() const
+ {
+ return false;
+ }
+ };
}
#endif
diff --git a/apps/opencs/model/world/columns.cpp b/apps/opencs/model/world/columns.cpp
index b206322582..a842e7b8de 100644
--- a/apps/opencs/model/world/columns.cpp
+++ b/apps/opencs/model/world/columns.cpp
@@ -3,6 +3,8 @@
#include <components/misc/stringops.hpp>
+#include "universalid.hpp"
+
namespace CSMWorld
{
namespace Columns
@@ -49,7 +51,7 @@ namespace CSMWorld
{ ColumnId_FactionIndex, "Faction Index" },
{ ColumnId_Charges, "Charges" },
{ ColumnId_Enchantment, "Enchantment" },
- { ColumnId_Value, "Coin Value" },
+ { ColumnId_CoinValue, "Coin Value" },
{ ColumnId_Teleport, "Teleport" },
{ ColumnId_TeleportCell, "Teleport Cell" },
{ ColumnId_LockLevel, "Lock Level" },
@@ -145,6 +147,20 @@ namespace CSMWorld
{ ColumnId_Magical, "Magical" },
{ ColumnId_Silver, "Silver" },
{ ColumnId_Filter, "Filter" },
+ { ColumnId_PositionXPos, "Pos X" },
+ { ColumnId_PositionYPos, "Pos Y" },
+ { ColumnId_PositionZPos, "Pos Z" },
+ { ColumnId_PositionXRot, "Rot X" },
+ { ColumnId_PositionYRot, "Rot Y" },
+ { ColumnId_PositionZRot, "Rot Z" },
+ { ColumnId_DoorPositionXPos, "Teleport Pos X" },
+ { ColumnId_DoorPositionYPos, "Teleport Pos Y" },
+ { ColumnId_DoorPositionZPos, "Teleport Pos Z" },
+ { ColumnId_DoorPositionXRot, "Teleport Rot X" },
+ { ColumnId_DoorPositionYRot, "Teleport Rot Y" },
+ { ColumnId_DoorPositionZRot, "Teleport Rot Z" },
+ { ColumnId_DialogueType, "Dialogue Type" },
+ { ColumnId_Scope, "Scope", },
{ ColumnId_UseValue1, "Use value 1" },
{ ColumnId_UseValue2, "Use value 2" },
@@ -196,4 +212,110 @@ int CSMWorld::Columns::getId (const std::string& name)
return sNames[i].mId;
return -1;
+}
+
+namespace
+{
+ static const char *sSpecialisations[] =
+ {
+ "Combat", "Magic", "Stealth", 0
+ };
+
+ static const char *sAttributes[] =
+ {
+ "Strength", "Intelligence", "Willpower", "Agility", "Speed", "Endurance", "Personality",
+ "Luck", 0
+ };
+
+ static const char *sSpellTypes[] =
+ {
+ "Spell", "Ability", "Blight", "Disease", "Curse", "Power", 0
+ };
+
+ static const char *sApparatusTypes[] =
+ {
+ "Mortar & Pestle", "Albemic", "Calcinator", "Retort", 0
+ };
+
+ static const char *sArmorTypes[] =
+ {
+ "Helmet", "Cuirass", "Left Pauldron", "Right Pauldron", "Greaves", "Boots", "Left Gauntlet",
+ "Right Gauntlet", "Shield", "Left Bracer", "Right Bracer", 0
+ };
+
+ static const char *sClothingTypes[] =
+ {
+ "Pants", "Shoes", "Shirt", "Belt", "Robe", "Right Glove", "Left Glove", "Skirt", "Ring",
+ "Amulet", 0
+ };
+
+ static const char *sCreatureTypes[] =
+ {
+ "Creature", "Deadra", "Undead", "Humanoid", 0
+ };
+
+ static const char *sWeaponTypes[] =
+ {
+ "Short Blade 1H", "Long Blade 1H", "Long Blade 2H", "Blunt 1H", "Blunt 2H Close",
+ "Blunt 2H Wide", "Spear 2H", "Axe 1H", "Axe 2H", "Bow", "Crossbow", "Thrown", "Arrow",
+ "Bolt", 0
+ };
+
+ static const char *sModificationEnums[] =
+ {
+ "Base", "Modified", "Added", "Deleted", "Deleted", 0
+ };
+
+ static const char *sVarTypeEnums[] =
+ {
+ "unknown", "none", "short", "integer", "long", "float", "string", 0
+ };
+
+ static const char *sDialogueTypeEnums[] =
+ {
+ "Topic", "Voice", "Greeting", "Persuasion", 0
+ };
+
+ const char **getEnumNames (CSMWorld::Columns::ColumnId column)
+ {
+ switch (column)
+ {
+ case CSMWorld::Columns::ColumnId_Specialisation: return sSpecialisations;
+ case CSMWorld::Columns::ColumnId_Attribute: return sAttributes;
+ case CSMWorld::Columns::ColumnId_SpellType: return sSpellTypes;
+ case CSMWorld::Columns::ColumnId_ApparatusType: return sApparatusTypes;
+ case CSMWorld::Columns::ColumnId_ArmorType: return sArmorTypes;
+ case CSMWorld::Columns::ColumnId_ClothingType: return sClothingTypes;
+ case CSMWorld::Columns::ColumnId_CreatureType: return sCreatureTypes;
+ case CSMWorld::Columns::ColumnId_WeaponType: return sWeaponTypes;
+ case CSMWorld::Columns::ColumnId_Modification: return sModificationEnums;
+ case CSMWorld::Columns::ColumnId_ValueType: return sVarTypeEnums;
+ case CSMWorld::Columns::ColumnId_DialogueType: return sDialogueTypeEnums;
+
+ default: return 0;
+ }
+ }
+}
+
+bool CSMWorld::Columns::hasEnums (ColumnId column)
+{
+ return getEnumNames (column)!=0 || column==ColumnId_RecordType;
+}
+
+std::vector<std::string> CSMWorld::Columns::getEnums (ColumnId column)
+{
+ std::vector<std::string> enums;
+
+ if (const char **table = getEnumNames (column))
+ for (int i=0; table[i]; ++i)
+ enums.push_back (table[i]);
+ else if (column==ColumnId_RecordType)
+ {
+ enums.push_back (""); // none
+
+ for (int i=UniversalId::Type_None+1; i<UniversalId::NumberOfTypes; ++i)
+ enums.push_back (UniversalId (static_cast<UniversalId::Type> (i)).getTypeName());
+ }
+
+ return enums;
} \ No newline at end of file
diff --git a/apps/opencs/model/world/columns.hpp b/apps/opencs/model/world/columns.hpp
index 9a39e16780..55d085a96f 100644
--- a/apps/opencs/model/world/columns.hpp
+++ b/apps/opencs/model/world/columns.hpp
@@ -2,6 +2,7 @@
#define CSM_WOLRD_COLUMNS_H
#include <string>
+#include <vector>
namespace CSMWorld
{
@@ -44,101 +45,115 @@ namespace CSMWorld
ColumnId_Charges = 32,
ColumnId_Enchantment = 33,
ColumnId_CoinValue = 34,
- ColumnId_Teleport = 25,
- ColumnId_TeleportCell = 26,
- ColumnId_LockLevel = 27,
- ColumnId_Key = 28,
- ColumnId_Trap = 29,
- ColumnId_BeastRace = 30,
- ColumnId_AutoCalc = 31,
- ColumnId_StarterSpell = 32,
- ColumnId_AlwaysSucceeds = 33,
- ColumnId_SleepForbidden = 34,
- ColumnId_InteriorWater = 35,
- ColumnId_InteriorSky = 36,
- ColumnId_Model = 37,
- ColumnId_Script = 38,
- ColumnId_Icon = 39,
- ColumnId_Weight = 40,
- ColumnId_EnchantmentPoints = 31,
- ColumnId_Quality = 32,
- ColumnId_Ai = 33,
- ColumnId_AiHello = 34,
- ColumnId_AiFlee = 35,
- ColumnId_AiFight = 36,
- ColumnId_AiAlarm = 37,
- ColumnId_BuysWeapons = 38,
- ColumnId_BuysArmor = 39,
- ColumnId_BuysClothing = 40,
- ColumnId_BuysBooks = 41,
- ColumnId_BuysIngredients = 42,
- ColumnId_BuysLockpicks = 43,
- ColumnId_BuysProbes = 44,
- ColumnId_BuysLights = 45,
- ColumnId_BuysApparati = 46,
- ColumnId_BuysRepairItems = 47,
- ColumnId_BuysMiscItems = 48,
- ColumnId_BuysPotions = 49,
- ColumnId_BuysMagicItems = 50,
- ColumnId_SellsSpells = 51,
- ColumnId_Trainer = 52,
- ColumnId_Spellmaking = 53,
- ColumnId_EnchantingService = 54,
- ColumnId_RepairService = 55,
- ColumnId_ApparatusType = 56,
- ColumnId_ArmorType = 57,
- ColumnId_Health = 58,
- ColumnId_ArmorValue = 59,
- ColumnId_Scroll = 60,
- ColumnId_ClothingType = 61,
- ColumnId_WeightCapacity = 62,
- ColumnId_OrganicContainer = 63,
- ColumnId_Respawn = 64,
- ColumnId_CreatureType = 65,
- ColumnId_SoulPoints = 66,
- ColumnId_OriginalCreature = 67,
- ColumnId_Biped = 68,
- ColumnId_HasWeapon = 69,
- ColumnId_NoMovement = 70,
- ColumnId_Swims = 71,
- ColumnId_Flies = 72,
- ColumnId_Walks = 73,
- ColumnId_Essential = 74,
- ColumnId_SkeletonBlood = 75,
- ColumnId_MetalBlood = 76,
- ColumnId_OpenSound = 77,
- ColumnId_CloseSound = 78,
- ColumnId_Duration = 79,
- ColumnId_Radius = 80,
- ColumnId_Colour = 81,
- ColumnId_Sound = 82,
- ColumnId_Dynamic = 83,
- ColumnId_Portable = 84,
- ColumnId_NegativeLight = 85,
- ColumnId_Flickering = 86,
- ColumnId_SlowFlickering = 87,
- ColumnId_Pulsing = 88,
- ColumnId_SlowPulsing = 89,
- ColumnId_Fire = 90,
- ColumnId_OffByDefault = 91,
- ColumnId_IsKey = 92,
- ColumnId_Race = 93,
- ColumnId_Class = 94,
- Columnid_Hair = 95,
- ColumnId_Head = 96,
- ColumnId_Female = 97,
- ColumnId_WeaponType = 98,
- ColumnId_WeaponSpeed = 99,
- ColumnId_WeaponReach = 100,
- ColumnId_MinChop = 101,
- ColumnId_MaxChip = 102,
- Columnid_MinSlash = 103,
- ColumnId_MaxSlash = 104,
- ColumnId_MinThrust = 105,
- ColumnId_MaxThrust = 106,
- ColumnId_Magical = 107,
- ColumnId_Silver = 108,
- ColumnId_Filter = 109,
+ ColumnId_Teleport = 35,
+ ColumnId_TeleportCell = 36,
+ ColumnId_LockLevel = 37,
+ ColumnId_Key = 38,
+ ColumnId_Trap = 39,
+ ColumnId_BeastRace = 40,
+ ColumnId_AutoCalc = 41,
+ ColumnId_StarterSpell = 42,
+ ColumnId_AlwaysSucceeds = 43,
+ ColumnId_SleepForbidden = 44,
+ ColumnId_InteriorWater = 45,
+ ColumnId_InteriorSky = 46,
+ ColumnId_Model = 47,
+ ColumnId_Script = 48,
+ ColumnId_Icon = 49,
+ ColumnId_Weight = 50,
+ ColumnId_EnchantmentPoints = 51,
+ ColumnId_Quality = 52,
+ ColumnId_Ai = 53,
+ ColumnId_AiHello = 54,
+ ColumnId_AiFlee = 55,
+ ColumnId_AiFight = 56,
+ ColumnId_AiAlarm = 57,
+ ColumnId_BuysWeapons = 58,
+ ColumnId_BuysArmor = 59,
+ ColumnId_BuysClothing = 60,
+ ColumnId_BuysBooks = 61,
+ ColumnId_BuysIngredients = 62,
+ ColumnId_BuysLockpicks = 63,
+ ColumnId_BuysProbes = 64,
+ ColumnId_BuysLights = 65,
+ ColumnId_BuysApparati = 66,
+ ColumnId_BuysRepairItems = 67,
+ ColumnId_BuysMiscItems = 68,
+ ColumnId_BuysPotions = 69,
+ ColumnId_BuysMagicItems = 70,
+ ColumnId_SellsSpells = 71,
+ ColumnId_Trainer = 72,
+ ColumnId_Spellmaking = 73,
+ ColumnId_EnchantingService = 74,
+ ColumnId_RepairService = 75,
+ ColumnId_ApparatusType = 76,
+ ColumnId_ArmorType = 77,
+ ColumnId_Health = 78,
+ ColumnId_ArmorValue = 79,
+ ColumnId_Scroll = 80,
+ ColumnId_ClothingType = 81,
+ ColumnId_WeightCapacity = 82,
+ ColumnId_OrganicContainer = 83,
+ ColumnId_Respawn = 84,
+ ColumnId_CreatureType = 85,
+ ColumnId_SoulPoints = 86,
+ ColumnId_OriginalCreature = 87,
+ ColumnId_Biped = 88,
+ ColumnId_HasWeapon = 89,
+ ColumnId_NoMovement = 90,
+ ColumnId_Swims = 91,
+ ColumnId_Flies = 92,
+ ColumnId_Walks = 93,
+ ColumnId_Essential = 94,
+ ColumnId_SkeletonBlood = 95,
+ ColumnId_MetalBlood = 96,
+ ColumnId_OpenSound = 97,
+ ColumnId_CloseSound = 98,
+ ColumnId_Duration = 99,
+ ColumnId_Radius = 100,
+ ColumnId_Colour = 101,
+ ColumnId_Sound = 102,
+ ColumnId_Dynamic = 103,
+ ColumnId_Portable = 104,
+ ColumnId_NegativeLight = 105,
+ ColumnId_Flickering = 106,
+ ColumnId_SlowFlickering = 107,
+ ColumnId_Pulsing = 108,
+ ColumnId_SlowPulsing = 109,
+ ColumnId_Fire = 110,
+ ColumnId_OffByDefault = 111,
+ ColumnId_IsKey = 112,
+ ColumnId_Race = 113,
+ ColumnId_Class = 114,
+ Columnid_Hair = 115,
+ ColumnId_Head = 116,
+ ColumnId_Female = 117,
+ ColumnId_WeaponType = 118,
+ ColumnId_WeaponSpeed = 119,
+ ColumnId_WeaponReach = 120,
+ ColumnId_MinChop = 121,
+ ColumnId_MaxChip = 122,
+ Columnid_MinSlash = 123,
+ ColumnId_MaxSlash = 124,
+ ColumnId_MinThrust = 125,
+ ColumnId_MaxThrust = 126,
+ ColumnId_Magical = 127,
+ ColumnId_Silver = 128,
+ ColumnId_Filter = 129,
+ ColumnId_PositionXPos = 130,
+ ColumnId_PositionYPos = 131,
+ ColumnId_PositionZPos = 132,
+ ColumnId_PositionXRot = 133,
+ ColumnId_PositionYRot = 134,
+ ColumnId_PositionZRot = 135,
+ ColumnId_DoorPositionXPos = 136,
+ ColumnId_DoorPositionYPos = 137,
+ ColumnId_DoorPositionZPos = 138,
+ ColumnId_DoorPositionXRot = 139,
+ ColumnId_DoorPositionYRot = 140,
+ ColumnId_DoorPositionZRot = 141,
+ ColumnId_DialogueType = 142,
+ ColumnId_Scope = 143,
// Allocated to a separate value range, so we don't get a collision should we ever need
// to extend the number of use values.
@@ -180,6 +195,11 @@ namespace CSMWorld
int getId (const std::string& name);
///< Will return -1 for an invalid name.
+
+ bool hasEnums (ColumnId column);
+
+ std::vector<std::string> getEnums (ColumnId column);
+ ///< Returns an empty vector, if \æ column isn't an enum type column.
}
}
diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp
index fbdbb44136..10e56765fa 100644
--- a/apps/opencs/model/world/data.cpp
+++ b/apps/opencs/model/world/data.cpp
@@ -2,12 +2,14 @@
#include "data.hpp"
#include <stdexcept>
+#include <algorithm>
#include <QAbstractItemModel>
#include <components/esm/esmreader.hpp>
#include <components/esm/defs.hpp>
#include <components/esm/loadglob.hpp>
+#include <components/esm/cellref.hpp>
#include "idtable.hpp"
#include "columnimp.hpp"
@@ -15,13 +17,42 @@
#include "columns.hpp"
void CSMWorld::Data::addModel (QAbstractItemModel *model, UniversalId::Type type1,
- UniversalId::Type type2)
+ UniversalId::Type type2, bool update)
{
mModels.push_back (model);
mModelIndex.insert (std::make_pair (type1, model));
if (type2!=UniversalId::Type_None)
mModelIndex.insert (std::make_pair (type2, model));
+
+ if (update)
+ {
+ connect (model, SIGNAL (dataChanged (const QModelIndex&, const QModelIndex&)),
+ this, SLOT (dataChanged (const QModelIndex&, const QModelIndex&)));
+ connect (model, SIGNAL (rowsInserted (const QModelIndex&, int, int)),
+ this, SLOT (rowsChanged (const QModelIndex&, int, int)));
+ connect (model, SIGNAL (rowsRemoved (const QModelIndex&, int, int)),
+ this, SLOT (rowsChanged (const QModelIndex&, int, int)));
+ }
+}
+
+void CSMWorld::Data::appendIds (std::vector<std::string>& ids, const CollectionBase& collection,
+ bool listDeleted)
+{
+ std::vector<std::string> ids2 = collection.getIds (listDeleted);
+
+ ids.insert (ids.end(), ids2.begin(), ids2.end());
+}
+
+int CSMWorld::Data::count (RecordBase::State state, const CollectionBase& collection)
+{
+ int number = 0;
+
+ for (int i=0; i<collection.getSize(); ++i)
+ if (collection.getRecord (i).mState==state)
+ ++number;
+
+ return number;
}
CSMWorld::Data::Data() : mRefs (mCells)
@@ -121,6 +152,14 @@ CSMWorld::Data::Data() : mRefs (mCells)
mSpells.addColumn (new FlagColumn<ESM::Spell> (Columns::ColumnId_StarterSpell, 0x2));
mSpells.addColumn (new FlagColumn<ESM::Spell> (Columns::ColumnId_AlwaysSucceeds, 0x4));
+ mTopics.addColumn (new StringIdColumn<ESM::Dialogue>);
+ mTopics.addColumn (new RecordStateColumn<ESM::Dialogue>);
+ mTopics.addColumn (new DialogueTypeColumn<ESM::Dialogue>);
+
+ mJournals.addColumn (new StringIdColumn<ESM::Dialogue>);
+ mJournals.addColumn (new RecordStateColumn<ESM::Dialogue>);
+ mJournals.addColumn (new DialogueTypeColumn<ESM::Dialogue> (true));
+
mCells.addColumn (new StringIdColumn<Cell>);
mCells.addColumn (new RecordStateColumn<Cell>);
mCells.addColumn (new FixedRecordTypeColumn<Cell> (UniversalId::Type_Cell));
@@ -134,6 +173,12 @@ CSMWorld::Data::Data() : mRefs (mCells)
mRefs.addColumn (new RecordStateColumn<CellRef>);
mRefs.addColumn (new CellColumn<CellRef>);
mRefs.addColumn (new IdColumn<CellRef>);
+ mRefs.addColumn (new PosColumn<CellRef> (&CellRef::mPos, 0, false));
+ mRefs.addColumn (new PosColumn<CellRef> (&CellRef::mPos, 1, false));
+ mRefs.addColumn (new PosColumn<CellRef> (&CellRef::mPos, 2, false));
+ mRefs.addColumn (new RotColumn<CellRef> (&CellRef::mPos, 0, false));
+ mRefs.addColumn (new RotColumn<CellRef> (&CellRef::mPos, 1, false));
+ mRefs.addColumn (new RotColumn<CellRef> (&CellRef::mPos, 2, false));
mRefs.addColumn (new ScaleColumn<CellRef>);
mRefs.addColumn (new OwnerColumn<CellRef>);
mRefs.addColumn (new SoulColumn<CellRef>);
@@ -144,6 +189,12 @@ CSMWorld::Data::Data() : mRefs (mCells)
mRefs.addColumn (new GoldValueColumn<CellRef>);
mRefs.addColumn (new TeleportColumn<CellRef>);
mRefs.addColumn (new TeleportCellColumn<CellRef>);
+ mRefs.addColumn (new PosColumn<CellRef> (&CellRef::mDoorDest, 0, true));
+ mRefs.addColumn (new PosColumn<CellRef> (&CellRef::mDoorDest, 1, true));
+ mRefs.addColumn (new PosColumn<CellRef> (&CellRef::mDoorDest, 2, true));
+ mRefs.addColumn (new RotColumn<CellRef> (&CellRef::mDoorDest, 0, true));
+ mRefs.addColumn (new RotColumn<CellRef> (&CellRef::mDoorDest, 1, true));
+ mRefs.addColumn (new RotColumn<CellRef> (&CellRef::mDoorDest, 2, true));
mRefs.addColumn (new LockLevelColumn<CellRef>);
mRefs.addColumn (new KeyColumn<CellRef>);
mRefs.addColumn (new TrapColumn<CellRef>);
@@ -152,10 +203,11 @@ CSMWorld::Data::Data() : mRefs (mCells)
mFilters.addColumn (new RecordStateColumn<CSMFilter::Filter>);
mFilters.addColumn (new FilterColumn<CSMFilter::Filter>);
mFilters.addColumn (new DescriptionColumn<CSMFilter::Filter>);
+ mFilters.addColumn (new ScopeColumn<CSMFilter::Filter>);
addModel (new IdTable (&mGlobals), UniversalId::Type_Globals, UniversalId::Type_Global);
addModel (new IdTable (&mGmsts), UniversalId::Type_Gmsts, UniversalId::Type_Gmst);
- addModel (new IdTable (&mSkills), UniversalId::Type_Skills, UniversalId::Type_Skill);
+ addModel (new IdTable (&mSkills), UniversalId::Type_Skills, UniversalId::Type_Skill, false);
addModel (new IdTable (&mClasses), UniversalId::Type_Classes, UniversalId::Type_Class);
addModel (new IdTable (&mFactions), UniversalId::Type_Factions, UniversalId::Type_Faction);
addModel (new IdTable (&mRaces), UniversalId::Type_Races, UniversalId::Type_Race);
@@ -164,11 +216,13 @@ CSMWorld::Data::Data() : mRefs (mCells)
addModel (new IdTable (&mRegions), UniversalId::Type_Regions, UniversalId::Type_Region);
addModel (new IdTable (&mBirthsigns), UniversalId::Type_Birthsigns, UniversalId::Type_Birthsign);
addModel (new IdTable (&mSpells), UniversalId::Type_Spells, UniversalId::Type_Spell);
+ addModel (new IdTable (&mTopics), UniversalId::Type_Topics, UniversalId::Type_Topic);
+ addModel (new IdTable (&mJournals), UniversalId::Type_Journals, UniversalId::Type_Journal);
addModel (new IdTable (&mCells), UniversalId::Type_Cells, UniversalId::Type_Cell);
addModel (new IdTable (&mReferenceables), UniversalId::Type_Referenceables,
UniversalId::Type_Referenceable);
- addModel (new IdTable (&mRefs), UniversalId::Type_References, UniversalId::Type_Reference);
- addModel (new IdTable (&mFilters), UniversalId::Type_Filters, UniversalId::Type_Filter);
+ addModel (new IdTable (&mRefs), UniversalId::Type_References, UniversalId::Type_Reference, false);
+ addModel (new IdTable (&mFilters), UniversalId::Type_Filters, UniversalId::Type_Filter, false);
}
CSMWorld::Data::~Data()
@@ -287,6 +341,28 @@ CSMWorld::IdCollection<ESM::Spell>& CSMWorld::Data::getSpells()
return mSpells;
}
+
+const CSMWorld::IdCollection<ESM::Dialogue>& CSMWorld::Data::getTopics() const
+{
+ return mTopics;
+}
+
+CSMWorld::IdCollection<ESM::Dialogue>& CSMWorld::Data::getTopics()
+{
+ return mTopics;
+}
+
+const CSMWorld::IdCollection<ESM::Dialogue>& CSMWorld::Data::getJournals() const
+{
+ return mJournals;
+}
+
+CSMWorld::IdCollection<ESM::Dialogue>& CSMWorld::Data::getJournals()
+{
+ return mJournals;
+}
+
+
const CSMWorld::IdCollection<CSMWorld::Cell>& CSMWorld::Data::getCells() const
{
return mCells;
@@ -341,7 +417,7 @@ QAbstractItemModel *CSMWorld::Data::getTableModel (const UniversalId& id)
{
RegionMap *table = 0;
addModel (table = new RegionMap (*this), UniversalId::Type_RegionMap,
- UniversalId::Type_None);
+ UniversalId::Type_None, false);
return table;
}
throw std::logic_error ("No table model available for " + id.toString());
@@ -355,7 +431,7 @@ void CSMWorld::Data::merge()
mGlobals.merge();
}
-void CSMWorld::Data::loadFile (const boost::filesystem::path& path, bool base)
+void CSMWorld::Data::loadFile (const boost::filesystem::path& path, bool base, bool project)
{
ESM::ESMReader reader;
@@ -365,6 +441,9 @@ void CSMWorld::Data::loadFile (const boost::filesystem::path& path, bool base)
reader.open (path.string());
+ mAuthor = reader.getAuthor();
+ mDescription = reader.getDesc();
+
// Note: We do not need to send update signals here, because at this point the model is not connected
// to any view.
while (reader.hasMoreRecs())
@@ -415,6 +494,54 @@ void CSMWorld::Data::loadFile (const boost::filesystem::path& path, bool base)
case ESM::REC_STAT: mReferenceables.load (reader, base, UniversalId::Type_Static); break;
case ESM::REC_WEAP: mReferenceables.load (reader, base, UniversalId::Type_Weapon); break;
+ case ESM::REC_DIAL:
+ {
+ std::string id = reader.getHNOString ("NAME");
+
+ ESM::Dialogue record;
+ record.mId = id;
+ record.load (reader);
+
+ if (record.mType==ESM::Dialogue::Journal)
+ {
+ mJournals.load (record, base);
+ }
+ else if (record.mType==ESM::Dialogue::Deleted)
+ {
+ if (mJournals.tryDelete (id))
+ {
+ /// \todo handle info records
+ }
+ else if (mTopics.tryDelete (id))
+ {
+ /// \todo handle info records
+ }
+ else
+ {
+ /// \todo report deletion of non-existing record
+ }
+ }
+ else
+ {
+ mTopics.load (record, base);
+ }
+
+ break;
+ }
+
+ case ESM::REC_FILT:
+
+ if (project)
+ {
+ mFilters.load (reader, base);
+ mFilters.setData (mFilters.getSize()-1,
+ mFilters.findColumnIndex (CSMWorld::Columns::ColumnId_Scope),
+ static_cast<int> (CSMFilter::Filter::Scope_Project));
+ break;
+ }
+
+ // fall through (filter record in a content file is an error with format 0)
+
default:
/// \todo throw an exception instead, once all records are implemented
@@ -437,6 +564,81 @@ bool CSMWorld::Data::hasId (const std::string& id) const
getRegions().searchId (id)!=-1 ||
getBirthsigns().searchId (id)!=-1 ||
getSpells().searchId (id)!=-1 ||
+ getTopics().searchId (id)!=-1 ||
+ getJournals().searchId (id)!=-1 ||
getCells().searchId (id)!=-1 ||
getReferenceables().searchId (id)!=-1;
}
+
+int CSMWorld::Data::count (RecordBase::State state) const
+{
+ return
+ count (state, mGlobals) +
+ count (state, mGmsts) +
+ count (state, mSkills) +
+ count (state, mClasses) +
+ count (state, mFactions) +
+ count (state, mRaces) +
+ count (state, mSounds) +
+ count (state, mScripts) +
+ count (state, mRegions) +
+ count (state, mBirthsigns) +
+ count (state, mSpells) +
+ count (state, mCells) +
+ count (state, mReferenceables);
+}
+
+void CSMWorld::Data::setDescription (const std::string& description)
+{
+ mDescription = description;
+}
+
+std::string CSMWorld::Data::getDescription() const
+{
+ return mDescription;
+}
+
+void CSMWorld::Data::setAuthor (const std::string& author)
+{
+ mAuthor = author;
+}
+
+std::string CSMWorld::Data::getAuthor() const
+{
+ return mAuthor;
+}
+
+std::vector<std::string> CSMWorld::Data::getIds (bool listDeleted) const
+{
+ std::vector<std::string> ids;
+
+ appendIds (ids, mGlobals, listDeleted);
+ appendIds (ids, mGmsts, listDeleted);
+ appendIds (ids, mClasses, listDeleted);
+ appendIds (ids, mFactions, listDeleted);
+ appendIds (ids, mRaces, listDeleted);
+ appendIds (ids, mSounds, listDeleted);
+ appendIds (ids, mScripts, listDeleted);
+ appendIds (ids, mRegions, listDeleted);
+ appendIds (ids, mBirthsigns, listDeleted);
+ appendIds (ids, mSpells, listDeleted);
+ appendIds (ids, mTopics, listDeleted);
+ appendIds (ids, mJournals, listDeleted);
+ appendIds (ids, mCells, listDeleted);
+ appendIds (ids, mReferenceables, listDeleted);
+
+ std::sort (ids.begin(), ids.end());
+
+ return ids;
+}
+
+void CSMWorld::Data::dataChanged (const QModelIndex& topLeft, const QModelIndex& bottomRight)
+{
+ if (topLeft.column()<=0)
+ emit idListChanged();
+}
+
+void CSMWorld::Data::rowsChanged (const QModelIndex& parent, int start, int end)
+{
+ emit idListChanged();
+} \ No newline at end of file
diff --git a/apps/opencs/model/world/data.hpp b/apps/opencs/model/world/data.hpp
index 2f8a2117e0..1a9eae2d26 100644
--- a/apps/opencs/model/world/data.hpp
+++ b/apps/opencs/model/world/data.hpp
@@ -6,6 +6,9 @@
#include <boost/filesystem/path.hpp>
+#include <QObject>
+#include <QModelIndex>
+
#include <components/esm/loadglob.hpp>
#include <components/esm/loadgmst.hpp>
#include <components/esm/loadskil.hpp>
@@ -17,6 +20,7 @@
#include <components/esm/loadregn.hpp>
#include <components/esm/loadbsgn.hpp>
#include <components/esm/loadspel.hpp>
+#include <components/esm/loaddial.hpp>
#include "../filter/filter.hpp"
@@ -30,8 +34,10 @@ class QAbstractItemModel;
namespace CSMWorld
{
- class Data
+ class Data : public QObject
{
+ Q_OBJECT
+
IdCollection<ESM::Global> mGlobals;
IdCollection<ESM::GameSetting> mGmsts;
IdCollection<ESM::Skill> mSkills;
@@ -43,25 +49,35 @@ namespace CSMWorld
IdCollection<ESM::Region> mRegions;
IdCollection<ESM::BirthSign> mBirthsigns;
IdCollection<ESM::Spell> mSpells;
+ IdCollection<ESM::Dialogue> mTopics;
+ IdCollection<ESM::Dialogue> mJournals;
IdCollection<Cell> mCells;
RefIdCollection mReferenceables;
RefCollection mRefs;
IdCollection<CSMFilter::Filter> mFilters;
std::vector<QAbstractItemModel *> mModels;
std::map<UniversalId::Type, QAbstractItemModel *> mModelIndex;
+ std::string mAuthor;
+ std::string mDescription;
// not implemented
Data (const Data&);
Data& operator= (const Data&);
void addModel (QAbstractItemModel *model, UniversalId::Type type1,
- UniversalId::Type type2 = UniversalId::Type_None);
+ UniversalId::Type type2 = UniversalId::Type_None, bool update = true);
+
+ static void appendIds (std::vector<std::string>& ids, const CollectionBase& collection,
+ bool listDeleted);
+ ///< Append all IDs from collection to \a ids.
+
+ static int count (RecordBase::State state, const CollectionBase& collection);
public:
Data();
- ~Data();
+ virtual ~Data();
const IdCollection<ESM::Global>& getGlobals() const;
@@ -107,6 +123,14 @@ namespace CSMWorld
IdCollection<ESM::Spell>& getSpells();
+ const IdCollection<ESM::Dialogue>& getTopics() const;
+
+ IdCollection<ESM::Dialogue>& getTopics();
+
+ const IdCollection<ESM::Dialogue>& getJournals() const;
+
+ IdCollection<ESM::Dialogue>& getJournals();
+
const IdCollection<Cell>& getCells() const;
IdCollection<Cell>& getCells();
@@ -132,10 +156,38 @@ namespace CSMWorld
void merge();
///< Merge modified into base.
- void loadFile (const boost::filesystem::path& path, bool base);
+ void loadFile (const boost::filesystem::path& path, bool base, bool project);
///< Merging content of a file into base or modified.
+ ///
+ /// \param project load project file instead of content file
bool hasId (const std::string& id) const;
+
+ std::vector<std::string> getIds (bool listDeleted = true) const;
+ ///< Return a sorted collection of all IDs that are not internal to the editor.
+ ///
+ /// \param listDeleted include deleted record in the list
+
+ int count (RecordBase::State state) const;
+ ///< Return number of top-level records with the given \a state.
+
+ void setDescription (const std::string& description);
+
+ std::string getDescription() const;
+
+ void setAuthor (const std::string& author);
+
+ std::string getAuthor() const;
+
+ signals:
+
+ void idListChanged();
+
+ private slots:
+
+ void dataChanged (const QModelIndex& topLeft, const QModelIndex& bottomRight);
+
+ void rowsChanged (const QModelIndex& parent, int start, int end);
};
}
diff --git a/apps/opencs/model/world/idcollection.hpp b/apps/opencs/model/world/idcollection.hpp
index 04e65eea7b..a7b37be5bc 100644
--- a/apps/opencs/model/world/idcollection.hpp
+++ b/apps/opencs/model/world/idcollection.hpp
@@ -7,21 +7,24 @@
namespace CSMWorld
{
-
/// \brief Single type collection of top level records
template<typename ESXRecordT, typename IdAccessorT = IdAccessor<ESXRecordT> >
class IdCollection : public Collection<ESXRecordT, IdAccessorT>
{
public:
- void load (ESM::ESMReader& reader, bool base,
- UniversalId::Type type = UniversalId::Type_None);
- ///< \param type Will be ignored, unless the collection supports multiple record types
+ void load (ESM::ESMReader& reader, bool base);
+
+ void load (const ESXRecordT& record, bool base);
+
+ bool tryDelete (const std::string& id);
+ ///< Try deleting \a id. If the id does not exist or can't be deleted the call is ignored.
+ ///
+ /// \return Has the ID been deleted?
};
template<typename ESXRecordT, typename IdAccessorT>
- void IdCollection<ESXRecordT, IdAccessorT>::load (ESM::ESMReader& reader, bool base,
- UniversalId::Type type)
+ void IdCollection<ESXRecordT, IdAccessorT>::load (ESM::ESMReader& reader, bool base)
{
std::string id = reader.getHNOString ("NAME");
@@ -56,30 +59,62 @@ namespace CSMWorld
IdAccessorT().getId (record) = id;
record.load (reader);
- int index = this->searchId (IdAccessorT().getId (record));
+ load (record, base);
+ }
+ }
- if (index==-1)
- {
- // new record
- Record<ESXRecordT> record2;
- record2.mState = base ? RecordBase::State_BaseOnly : RecordBase::State_ModifiedOnly;
- (base ? record2.mBase : record2.mModified) = record;
+ template<typename ESXRecordT, typename IdAccessorT>
+ void IdCollection<ESXRecordT, IdAccessorT>::load (const ESXRecordT& record, bool base)
+ {
+ int index = this->searchId (IdAccessorT().getId (record));
- this->appendRecord (record2);
- }
+ if (index==-1)
+ {
+ // new record
+ Record<ESXRecordT> record2;
+ record2.mState = base ? RecordBase::State_BaseOnly : RecordBase::State_ModifiedOnly;
+ (base ? record2.mBase : record2.mModified) = record;
+
+ this->appendRecord (record2);
+ }
+ else
+ {
+ // old record
+ Record<ESXRecordT> record2 = Collection<ESXRecordT, IdAccessorT>::getRecord (index);
+
+ if (base)
+ record2.mBase = record;
else
- {
- // old record
- Record<ESXRecordT> record2 = Collection<ESXRecordT, IdAccessorT>::getRecord (index);
+ record2.setModified (record);
- if (base)
- record2.mBase = record;
- else
- record2.setModified (record);
+ this->setRecord (index, record2);
+ }
+ }
- this->setRecord (index, record2);
- }
+ template<typename ESXRecordT, typename IdAccessorT>
+ bool IdCollection<ESXRecordT, IdAccessorT>::tryDelete (const std::string& id)
+ {
+ int index = this->searchId (id);
+
+ if (index==-1)
+ return false;
+
+ Record<ESXRecordT> record = Collection<ESXRecordT, IdAccessorT>::getRecord (index);
+
+ if (record.isDeleted())
+ return false;
+
+ if (record.mState==RecordBase::State_ModifiedOnly)
+ {
+ Collection<ESXRecordT, IdAccessorT>::removeRows (index, 1);
}
+ else
+ {
+ record.mState = RecordBase::State_Deleted;
+ this->setRecord (index, record);
+ }
+
+ return true;
}
}
diff --git a/apps/opencs/model/world/idtable.cpp b/apps/opencs/model/world/idtable.cpp
index baaf75289c..b7b1a9db05 100644
--- a/apps/opencs/model/world/idtable.cpp
+++ b/apps/opencs/model/world/idtable.cpp
@@ -161,21 +161,10 @@ const CSMWorld::RecordBase& CSMWorld::IdTable::getRecord (const std::string& id)
int CSMWorld::IdTable::searchColumnIndex (Columns::ColumnId id) const
{
- int columns = mIdCollection->getColumns();
-
- for (int i=0; i<columns; ++i)
- if (mIdCollection->getColumn (i).mColumnId==id)
- return i;
-
- return -1;
+ return mIdCollection->searchColumnIndex (id);
}
int CSMWorld::IdTable::findColumnIndex (Columns::ColumnId id) const
{
- int index = searchColumnIndex (id);
-
- if (index==-1)
- throw std::logic_error ("invalid column index");
-
- return index;
+ return mIdCollection->findColumnIndex (id);
} \ No newline at end of file
diff --git a/apps/opencs/model/world/refcollection.cpp b/apps/opencs/model/world/refcollection.cpp
index 085817753e..696aeefaa2 100644
--- a/apps/opencs/model/world/refcollection.cpp
+++ b/apps/opencs/model/world/refcollection.cpp
@@ -6,10 +6,6 @@
#include "ref.hpp"
#include "cell.hpp"
-CSMWorld::RefCollection::RefCollection (Collection<Cell>& cells)
-: mCells (cells), mNextId (0)
-{}
-
void CSMWorld::RefCollection::load (ESM::ESMReader& reader, int cellIndex, bool base)
{
Record<Cell> cell = mCells.getRecord (cellIndex);
diff --git a/apps/opencs/model/world/refcollection.hpp b/apps/opencs/model/world/refcollection.hpp
index 895315a179..b5f8c8064a 100644
--- a/apps/opencs/model/world/refcollection.hpp
+++ b/apps/opencs/model/world/refcollection.hpp
@@ -16,8 +16,10 @@ namespace CSMWorld
int mNextId;
public:
-
- RefCollection (Collection<Cell>& cells);
+ // MSVC needs the constructor for a class inheriting a template to be defined in header
+ RefCollection (Collection<Cell>& cells)
+ : mCells (cells), mNextId (0)
+ {}
void load (ESM::ESMReader& reader, int cellIndex, bool base);
///< Load a sequence of references.
diff --git a/apps/opencs/model/world/refidcollection.cpp b/apps/opencs/model/world/refidcollection.cpp
index 343cbe302a..3a6f70d310 100644
--- a/apps/opencs/model/world/refidcollection.cpp
+++ b/apps/opencs/model/world/refidcollection.cpp
@@ -534,3 +534,13 @@ int CSMWorld::RefIdCollection::getAppendIndex (UniversalId::Type type) const
{
return mData.getAppendIndex (type);
}
+
+std::vector<std::string> CSMWorld::RefIdCollection::getIds (bool listDeleted) const
+{
+ return mData.getIds (listDeleted);
+}
+
+void CSMWorld::RefIdCollection::save (int index, ESM::ESMWriter& writer) const
+{
+ mData.save (index, writer);
+} \ No newline at end of file
diff --git a/apps/opencs/model/world/refidcollection.hpp b/apps/opencs/model/world/refidcollection.hpp
index c10d1d2d0f..a479735db5 100644
--- a/apps/opencs/model/world/refidcollection.hpp
+++ b/apps/opencs/model/world/refidcollection.hpp
@@ -9,6 +9,11 @@
#include "collectionbase.hpp"
#include "refiddata.hpp"
+namespace ESM
+{
+ class ESMWriter;
+}
+
namespace CSMWorld
{
class RefIdAdapter;
@@ -89,6 +94,13 @@ namespace CSMWorld
virtual int getAppendIndex (UniversalId::Type type) const;
///< \param type Will be ignored, unless the collection supports multiple record types
+
+ virtual std::vector<std::string> getIds (bool listDeleted) const;
+ ///< Return a sorted collection of all IDs
+ ///
+ /// \param listDeleted include deleted record in the list
+
+ void save (int index, ESM::ESMWriter& writer) const;
};
}
diff --git a/apps/opencs/model/world/refiddata.cpp b/apps/opencs/model/world/refiddata.cpp
index c95db045f5..8f59b0fe74 100644
--- a/apps/opencs/model/world/refiddata.cpp
+++ b/apps/opencs/model/world/refiddata.cpp
@@ -196,3 +196,38 @@ int CSMWorld::RefIdData::getSize() const
{
return mIndex.size();
}
+
+std::vector<std::string> CSMWorld::RefIdData::getIds (bool listDeleted) const
+{
+ std::vector<std::string> ids;
+
+ for (std::map<std::string, LocalIndex>::const_iterator iter (mIndex.begin()); iter!=mIndex.end();
+ ++iter)
+ {
+ if (listDeleted || !getRecord (iter->second).isDeleted())
+ {
+ std::map<UniversalId::Type, RefIdDataContainerBase *>::const_iterator container =
+ mRecordContainers.find (iter->second.second);
+
+ if (container==mRecordContainers.end())
+ throw std::logic_error ("Invalid referenceable ID type");
+
+ ids.push_back (container->second->getId (iter->second.first));
+ }
+ }
+
+ return ids;
+}
+
+void CSMWorld::RefIdData::save (int index, ESM::ESMWriter& writer) const
+{
+ LocalIndex localIndex = globalToLocalIndex (index);
+
+ std::map<UniversalId::Type, RefIdDataContainerBase *>::const_iterator iter =
+ mRecordContainers.find (localIndex.second);
+
+ if (iter==mRecordContainers.end())
+ throw std::logic_error ("invalid local index type");
+
+ iter->second->save (localIndex.first, writer);
+} \ No newline at end of file
diff --git a/apps/opencs/model/world/refiddata.hpp b/apps/opencs/model/world/refiddata.hpp
index 475566fb54..9595ab23b5 100644
--- a/apps/opencs/model/world/refiddata.hpp
+++ b/apps/opencs/model/world/refiddata.hpp
@@ -23,6 +23,7 @@
#include <components/esm/loadweap.hpp>
#include <components/esm/loadnpc.hpp>
#include <components/esm/loadmisc.hpp>
+#include <components/esm/esmwriter.hpp>
#include "record.hpp"
#include "universalid.hpp"
@@ -51,6 +52,8 @@ namespace CSMWorld
virtual void erase (int index, int count) = 0;
virtual std::string getId (int index) const = 0;
+
+ virtual void save (int index, ESM::ESMWriter& writer) const = 0;
};
template<typename RecordT>
@@ -71,6 +74,8 @@ namespace CSMWorld
virtual void erase (int index, int count);
virtual std::string getId (int index) const;
+
+ virtual void save (int index, ESM::ESMWriter& writer) const;
};
template<typename RecordT>
@@ -123,6 +128,31 @@ namespace CSMWorld
return mContainer.at (index).get().mId;
}
+ template<typename RecordT>
+ void RefIdDataContainer<RecordT>::save (int index, ESM::ESMWriter& writer) const
+ {
+ CSMWorld::RecordBase::State state = mContainer.at (index).mState;
+
+ if (state==CSMWorld::RecordBase::State_Modified ||
+ state==CSMWorld::RecordBase::State_ModifiedOnly)
+ {
+ std::string type;
+ for (int i=0; i<4; ++i)
+ /// \todo make endianess agnostic (change ESMWriter interface?)
+ type += reinterpret_cast<const char *> (&mContainer.at (index).mModified.sRecordId)[i];
+
+ writer.startRecord (type);
+ writer.writeHNCString ("NAME", getId (index));
+ mContainer.at (index).mModified.save (writer);
+ writer.endRecord (type);
+ }
+ else if (state==CSMWorld::RecordBase::State_Deleted)
+ {
+ /// \todo write record with delete flag
+ }
+ }
+
+
class RefIdData
{
public:
@@ -182,6 +212,13 @@ namespace CSMWorld
void load (const LocalIndex& index, ESM::ESMReader& reader, bool base);
int getSize() const;
+
+ std::vector<std::string> getIds (bool listDeleted = true) const;
+ ///< Return a sorted collection of all IDs
+ ///
+ /// \param listDeleted include deleted record in the list
+
+ void save (int index, ESM::ESMWriter& writer) const;
};
}
diff --git a/apps/opencs/model/world/scriptcontext.cpp b/apps/opencs/model/world/scriptcontext.cpp
index 69b72abf26..86689d823b 100644
--- a/apps/opencs/model/world/scriptcontext.cpp
+++ b/apps/opencs/model/world/scriptcontext.cpp
@@ -1,6 +1,14 @@
#include "scriptcontext.hpp"
+#include <algorithm>
+
+#include <components/misc/stringops.hpp>
+
+#include "data.hpp"
+
+CSMWorld::ScriptContext::ScriptContext (const Data& data) : mData (data), mIdsUpdated (false) {}
+
bool CSMWorld::ScriptContext::canDeclareLocals() const
{
return false;
@@ -18,5 +26,19 @@ char CSMWorld::ScriptContext::getMemberType (const std::string& name, const std:
bool CSMWorld::ScriptContext::isId (const std::string& name) const
{
- return false;
+ if (!mIdsUpdated)
+ {
+ mIds = mData.getIds();
+
+ std::for_each (mIds.begin(), mIds.end(), &Misc::StringUtils::lowerCase);
+
+ mIdsUpdated = true;
+ }
+
+ return std::binary_search (mIds.begin(), mIds.end(), Misc::StringUtils::lowerCase (name));
+}
+
+void CSMWorld::ScriptContext::invalidateIds()
+{
+ mIdsUpdated = false;
} \ No newline at end of file
diff --git a/apps/opencs/model/world/scriptcontext.hpp b/apps/opencs/model/world/scriptcontext.hpp
index 1231aea649..b839b5a432 100644
--- a/apps/opencs/model/world/scriptcontext.hpp
+++ b/apps/opencs/model/world/scriptcontext.hpp
@@ -1,14 +1,25 @@
#ifndef CSM_WORLD_SCRIPTCONTEXT_H
#define CSM_WORLD_SCRIPTCONTEXT_H
+#include <string>
+#include <vector>
+
#include <components/compiler/context.hpp>
namespace CSMWorld
{
+ class Data;
+
class ScriptContext : public Compiler::Context
{
+ const Data& mData;
+ mutable std::vector<std::string> mIds;
+ mutable bool mIdsUpdated;
+
public:
+ ScriptContext (const Data& data);
+
virtual bool canDeclareLocals() const;
///< Is the compiler allowed to declare local variables?
@@ -20,6 +31,8 @@ namespace CSMWorld
virtual bool isId (const std::string& name) const;
///< Does \a name match an ID, that can be referenced?
+
+ void invalidateIds();
};
}
diff --git a/apps/opencs/model/world/universalid.cpp b/apps/opencs/model/world/universalid.cpp
index 42ebd1f807..6201a3cdaa 100644
--- a/apps/opencs/model/world/universalid.cpp
+++ b/apps/opencs/model/world/universalid.cpp
@@ -29,6 +29,8 @@ namespace
{ CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Regions, "Regions", 0 },
{ CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Birthsigns, "Birthsigns", 0 },
{ CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Spells, "Spells", 0 },
+ { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Topics, "Topics", 0 },
+ { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Journals, "Journals", 0 },
{ CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Cells, "Cells", 0 },
{ CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Referenceables,
"Referenceables", 0 },
@@ -43,18 +45,20 @@ namespace
static const TypeData sIdArg[] =
{
- { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Global, "Global Variable", 0 },
- { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Gmst, "Game Setting", 0 },
- { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Skill, "Skill", 0 },
- { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Class, "Class", 0 },
- { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Faction, "Faction", 0 },
- { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Race, "Race", 0 },
- { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Sound, "Sound", 0 },
- { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Script, "Script", 0 },
- { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Region, "Region", 0 },
- { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Birthsign, "Birthsign", 0 },
- { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Spell, "Spell", 0 },
- { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Cell, "Cell", 0 },
+ { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Global, "Global Variable", ":./globvar.png" },
+ { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Gmst, "Game Setting", ":./GMST.png" },
+ { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Skill, "Skill", ":./skill.png" },
+ { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Class, "Class", ":./class.png" },
+ { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Faction, "Faction", ":./faction.png" },
+ { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Race, "Race", ":./race.png" },
+ { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Sound, "Sound", ":./sound.png" },
+ { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Script, "Script", ":./script.png" },
+ { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Region, "Region", ":./land.png" },
+ { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Birthsign, "Birthsign", ":./birthsign.png" },
+ { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Spell, "Spell", ":./spell.png" },
+ { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Topic, "Topic", 0 },
+ { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Journal, "Journal", 0 },
+ { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Cell, "Cell", ":./cell.png" },
{ CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Referenceable, "Referenceables", 0 },
{ CSMWorld::UniversalId::Class_RefRecord, CSMWorld::UniversalId::Type_Activator, "Activator", ":./activator.png" },
{ CSMWorld::UniversalId::Class_RefRecord, CSMWorld::UniversalId::Type_Potion, "Potion", ":./potion.png" },
@@ -80,18 +84,17 @@ namespace
{ CSMWorld::UniversalId::Class_RefRecord, CSMWorld::UniversalId::Type_Static, "Static", ":./static.png" },
{ CSMWorld::UniversalId::Class_RefRecord, CSMWorld::UniversalId::Type_Weapon, "Weapon", ":./weapon.png" },
{ CSMWorld::UniversalId::Class_SubRecord, CSMWorld::UniversalId::Type_Reference, "Reference", 0 },
-
+ { CSMWorld::UniversalId::Class_SubRecord, CSMWorld::UniversalId::Type_Filter, "Filter", ":./filter.png" },
{ CSMWorld::UniversalId::Class_None, CSMWorld::UniversalId::Type_None, 0, 0 } // end marker
};
static const TypeData sIndexArg[] =
{
{ CSMWorld::UniversalId::Class_Transient, CSMWorld::UniversalId::Type_VerificationResults, "Verification Results", 0 },
+ { CSMWorld::UniversalId::Class_Collection, CSMWorld::UniversalId::Type_Scene, "Scene", 0 },
{ CSMWorld::UniversalId::Class_None, CSMWorld::UniversalId::Type_None, 0, 0 } // end marker
};
-
- static const unsigned int IDARG_SIZE = sizeof (sIdArg) / sizeof (TypeData);
}
CSMWorld::UniversalId::UniversalId (const std::string& universalId)
@@ -151,6 +154,22 @@ CSMWorld::UniversalId::UniversalId (Type type) : mArgumentType (ArgumentType_Non
return;
}
+ for (int i=0; sIdArg[i].mName; ++i)
+ if (type==sIdArg[i].mType)
+ {
+ mArgumentType = ArgumentType_Id;
+ mClass = sIdArg[i].mClass;
+ return;
+ }
+
+ for (int i=0; sIndexArg[i].mName; ++i)
+ if (type==sIndexArg[i].mType)
+ {
+ mArgumentType = ArgumentType_Index;
+ mClass = sIndexArg[i].mClass;
+ return;
+ }
+
throw std::logic_error ("invalid argument-less UniversalId type");
}
@@ -293,25 +312,6 @@ std::vector<CSMWorld::UniversalId::Type> CSMWorld::UniversalId::listReferenceabl
return list;
}
-std::pair<int, const char *> CSMWorld::UniversalId::getIdArgPair (unsigned int index)
-{
- std::pair<int, const char *> retPair;
-
- if ( index < IDARG_SIZE )
- {
- retPair.first = sIdArg[index].mType;
- retPair.second = sIdArg[index].mName;
- }
-
- return retPair;
-}
-
-unsigned int CSMWorld::UniversalId::getIdArgSize()
-{
- return IDARG_SIZE;
-}
-
-
bool CSMWorld::operator== (const CSMWorld::UniversalId& left, const CSMWorld::UniversalId& right)
{
return left.isEqual (right);
diff --git a/apps/opencs/model/world/universalid.hpp b/apps/opencs/model/world/universalid.hpp
index 8042c3dfdf..ffd99e572f 100644
--- a/apps/opencs/model/world/universalid.hpp
+++ b/apps/opencs/model/world/universalid.hpp
@@ -34,7 +34,7 @@ namespace CSMWorld
enum Type
{
- Type_None,
+ Type_None = 0,
Type_Globals,
Type_Global,
Type_VerificationResults,
@@ -86,9 +86,16 @@ namespace CSMWorld
Type_Reference,
Type_RegionMap,
Type_Filter,
- Type_Filters
+ Type_Filters,
+ Type_Topics,
+ Type_Topic,
+ Type_Journals,
+ Type_Journal,
+ Type_Scene
};
+ enum { NumberOfTypes = Type_Scene+1 };
+
private:
Class mClass;
@@ -102,7 +109,6 @@ namespace CSMWorld
UniversalId (const std::string& universalId);
UniversalId (Type type = Type_None);
- ///< Using a type for a non-argument-less UniversalId will throw an exception.
UniversalId (Type type, const std::string& id);
///< Using a type for a non-ID-argument UniversalId will throw an exception.
@@ -134,9 +140,6 @@ namespace CSMWorld
///< Will return an empty string, if no icon is available.
static std::vector<Type> listReferenceableTypes();
-
- static std::pair<int, const char *> getIdArgPair (unsigned int index);
- static unsigned int getIdArgSize ();
};
bool operator== (const UniversalId& left, const UniversalId& right);
diff --git a/apps/opencs/ocspropertywidget.cpp b/apps/opencs/ocspropertywidget.cpp
deleted file mode 100644
index 68315201ae..0000000000
--- a/apps/opencs/ocspropertywidget.cpp
+++ /dev/null
@@ -1,6 +0,0 @@
-#include "ocspropertywidget.hpp"
-
-OcsPropertyWidget::OcsPropertyWidget(QObject *parent) :
- QObject(parent)
-{
-}
diff --git a/apps/opencs/ocspropertywidget.hpp b/apps/opencs/ocspropertywidget.hpp
deleted file mode 100644
index fc64a0a692..0000000000
--- a/apps/opencs/ocspropertywidget.hpp
+++ /dev/null
@@ -1,18 +0,0 @@
-#ifndef OCSPROPERTYWIDGET_HPP
-#define OCSPROPERTYWIDGET_HPP
-
-#include <QObject>
-
-class OcsPropertyWidget : public QObject
-{
- Q_OBJECT
-public:
- explicit OcsPropertyWidget(QObject *parent = 0);
-
-signals:
-
-public slots:
-
-};
-
-#endif // OCSPROPERTYWIDGET_HPP
diff --git a/apps/opencs/view/doc/adjusterwidget.cpp b/apps/opencs/view/doc/adjusterwidget.cpp
new file mode 100644
index 0000000000..09e58690fc
--- /dev/null
+++ b/apps/opencs/view/doc/adjusterwidget.cpp
@@ -0,0 +1,115 @@
+
+#include "adjusterwidget.hpp"
+
+#include <stdexcept>
+#include <string>
+
+#include <boost/filesystem.hpp>
+
+#include <QHBoxLayout>
+#include <QLabel>
+#include <QStyle>
+
+CSVDoc::AdjusterWidget::AdjusterWidget (QWidget *parent)
+ : QWidget (parent), mValid (false), mAction (ContentAction_Undefined)
+{
+ QHBoxLayout *layout = new QHBoxLayout (this);
+
+ mIcon = new QLabel (this);
+
+ layout->addWidget (mIcon, 0);
+
+ mMessage = new QLabel (this);
+ mMessage->setWordWrap (true);
+ mMessage->setSizePolicy (QSizePolicy (QSizePolicy::Minimum, QSizePolicy::Minimum));
+
+ layout->addWidget (mMessage, 1);
+
+ setName ("", false);
+
+ setLayout (layout);
+}
+
+void CSVDoc::AdjusterWidget::setAction (ContentAction action)
+{
+ mAction = action;
+}
+
+void CSVDoc::AdjusterWidget::setLocalData (const boost::filesystem::path& localData)
+{
+ mLocalData = localData;
+}
+
+boost::filesystem::path CSVDoc::AdjusterWidget::getPath() const
+{
+ if (!mValid)
+ throw std::logic_error ("invalid content file path");
+
+ return mResultPath;
+}
+
+bool CSVDoc::AdjusterWidget::isValid() const
+{
+ return mValid;
+}
+
+void CSVDoc::AdjusterWidget::setFilenameCheck (bool doCheck)
+{
+ mDoFilenameCheck = doCheck;
+}
+
+void CSVDoc::AdjusterWidget::setName (const QString& name, bool addon)
+{
+ QString message;
+
+ mValid = (!name.isEmpty());
+
+ if (!mValid)
+ {
+ message = "No name.";
+ }
+ else
+ {
+ boost::filesystem::path path (name.toUtf8().data());
+
+ bool isLegacyPath = (path.extension() == ".esm" ||
+ path.extension() == ".esp");
+
+ bool isFilePathChanged = (path.parent_path().string() != mLocalData.string());
+
+ if (isLegacyPath)
+ path.replace_extension (addon ? ".omwaddon" : ".omwgame");
+
+ //if the file came from data-local and is not a legacy file to be converted,
+ //don't worry about doing a file check.
+ if (!isFilePathChanged && !isLegacyPath)
+ {
+ // path already points to the local data directory
+ message = QString::fromUtf8 (("Will be saved as: " + path.string()).c_str());
+ mResultPath = path;
+ }
+ //in all other cases, ensure the path points to data-local and do an existing file check
+ else
+ {
+ // path points somewhere else or is a leaf name.
+ if (isFilePathChanged)
+ path = mLocalData / path.filename();
+
+ message = QString::fromUtf8 (("Will be saved as: " + path.string()).c_str());
+ mResultPath = path;
+
+ if (boost::filesystem::exists (path))
+ {
+ /// \todo add an user setting to make this an error.
+ message += "<p>A file with the same name already exists. If you continue, it will be overwritten.";
+ }
+ }
+ }
+
+ mMessage->setText (message);
+ mIcon->setPixmap (style()->standardIcon (
+ mValid ? QStyle::SP_MessageBoxInformation : QStyle::SP_MessageBoxWarning).
+ pixmap (QSize (16, 16)));
+
+ emit stateChanged (mValid);
+}
diff --git a/apps/opencs/view/doc/adjusterwidget.hpp b/apps/opencs/view/doc/adjusterwidget.hpp
new file mode 100644
index 0000000000..91e308236f
--- /dev/null
+++ b/apps/opencs/view/doc/adjusterwidget.hpp
@@ -0,0 +1,56 @@
+#ifndef CSV_DOC_ADJUSTERWIDGET_H
+#define CSV_DOC_ADJUSTERWIDGET_H
+
+#include <boost/filesystem/path.hpp>
+
+#include <QWidget>
+
+class QLabel;
+
+namespace CSVDoc
+{
+ enum ContentAction
+ {
+ ContentAction_New,
+ ContentAction_Edit,
+ ContentAction_Undefined
+ };
+
+ class AdjusterWidget : public QWidget
+ {
+ Q_OBJECT
+
+ public:
+
+ boost::filesystem::path mLocalData;
+ QLabel *mMessage;
+ QLabel *mIcon;
+ bool mValid;
+ boost::filesystem::path mResultPath;
+ ContentAction mAction;
+ bool mDoFilenameCheck;
+
+ public:
+
+ AdjusterWidget (QWidget *parent = 0);
+
+ void setLocalData (const boost::filesystem::path& localData);
+ void setAction (ContentAction action);
+
+ void setFilenameCheck (bool doCheck);
+ bool isValid() const;
+
+ boost::filesystem::path getPath() const;
+ ///< This function must not be called if there is no valid path.
+
+ public slots:
+
+ void setName (const QString& name, bool addon);
+
+ signals:
+
+ void stateChanged (bool valid);
+ };
+}
+
+#endif
diff --git a/apps/opencs/view/doc/filedialog.cpp b/apps/opencs/view/doc/filedialog.cpp
index f956317a71..ab56415a14 100644
--- a/apps/opencs/view/doc/filedialog.cpp
+++ b/apps/opencs/view/doc/filedialog.cpp
@@ -9,264 +9,166 @@
#include <QSpacerItem>
#include <QPushButton>
#include <QLabel>
+#include <QGroupBox>
-#include <components/fileorderlist/model/datafilesmodel.hpp>
-#include <components/fileorderlist/model/pluginsproxymodel.hpp>
-#include <components/fileorderlist/model/esm/esmfile.hpp>
+#include "components/contentselector/model/esmfile.hpp"
+#include "components/contentselector/view/contentselector.hpp"
-#include <components/fileorderlist/utils/lineedit.hpp>
+#include "filewidget.hpp"
+#include "adjusterwidget.hpp"
-FileDialog::FileDialog(QWidget *parent) :
- QDialog(parent)
+CSVDoc::FileDialog::FileDialog(QWidget *parent) :
+ QDialog(parent), mSelector (0), mFileWidget (0), mAdjusterWidget (0)
{
- setupUi(this);
+ ui.setupUi (this);
+ resize(400, 400);
- // Models
- mDataFilesModel = new DataFilesModel(this);
-
- mMastersProxyModel = new QSortFilterProxyModel();
- mMastersProxyModel->setFilterRegExp(QString("^.*\\.esm"));
- mMastersProxyModel->setFilterCaseSensitivity(Qt::CaseInsensitive);
- mMastersProxyModel->setSourceModel(mDataFilesModel);
-
- mPluginsProxyModel = new PluginsProxyModel();
- mPluginsProxyModel->setFilterRegExp(QString("^.*\\.esp"));
- mPluginsProxyModel->setFilterCaseSensitivity(Qt::CaseInsensitive);
- mPluginsProxyModel->setSourceModel(mDataFilesModel);
-
- mFilterProxyModel = new QSortFilterProxyModel();
- mFilterProxyModel->setDynamicSortFilter(true);
- mFilterProxyModel->setSourceModel(mPluginsProxyModel);
-
- QCheckBox checkBox;
- unsigned int height = checkBox.sizeHint().height() + 4;
+ setObjectName ("FileDialog");
+ mSelector = new ContentSelectorView::ContentSelector (ui.contentSelectorWidget);
+ mAdjusterWidget = new AdjusterWidget (this);
+}
- mastersTable->setModel(mMastersProxyModel);
- mastersTable->setObjectName("MastersTable");
- mastersTable->setContextMenuPolicy(Qt::CustomContextMenu);
- mastersTable->setSortingEnabled(false);
- mastersTable->setSelectionBehavior(QAbstractItemView::SelectRows);
- mastersTable->setSelectionMode(QAbstractItemView::ExtendedSelection);
- mastersTable->setEditTriggers(QAbstractItemView::NoEditTriggers);
- mastersTable->setAlternatingRowColors(true);
- mastersTable->horizontalHeader()->setStretchLastSection(true);
+void CSVDoc::FileDialog::addFiles(const QString &path)
+{
+ mSelector->addFiles(path);
+}
- // Set the row height to the size of the checkboxes
- mastersTable->verticalHeader()->setDefaultSectionSize(height);
- mastersTable->verticalHeader()->setResizeMode(QHeaderView::Fixed);
- mastersTable->verticalHeader()->hide();
+QStringList CSVDoc::FileDialog::selectedFilePaths()
+{
+ QStringList filePaths;
- pluginsTable->setModel(mFilterProxyModel);
- pluginsTable->setObjectName("PluginsTable");
- pluginsTable->setContextMenuPolicy(Qt::CustomContextMenu);
- pluginsTable->setSortingEnabled(false);
- pluginsTable->setSelectionBehavior(QAbstractItemView::SelectRows);
- pluginsTable->setSelectionMode(QAbstractItemView::ExtendedSelection);
- pluginsTable->setEditTriggers(QAbstractItemView::NoEditTriggers);
- pluginsTable->setAlternatingRowColors(true);
- pluginsTable->setVerticalScrollMode(QAbstractItemView::ScrollPerItem);
- pluginsTable->horizontalHeader()->setStretchLastSection(true);
+ foreach (ContentSelectorModel::EsmFile *file, mSelector->selectedFiles() )
+ filePaths.append(file->filePath());
- pluginsTable->verticalHeader()->setDefaultSectionSize(height);
- pluginsTable->verticalHeader()->setResizeMode(QHeaderView::Fixed);
+ return filePaths;
+}
- // Hide the profile elements
- profileLabel->hide();
- profilesComboBox->hide();
- newProfileButton->hide();
- deleteProfileButton->hide();
+void CSVDoc::FileDialog::setLocalData (const boost::filesystem::path& localData)
+{
+ mAdjusterWidget->setLocalData (localData);
+}
- // Add some extra widgets
- QHBoxLayout *nameLayout = new QHBoxLayout();
- QSpacerItem *spacer = new QSpacerItem(40, 20, QSizePolicy::Expanding, QSizePolicy::Minimum);
+void CSVDoc::FileDialog::showDialog (ContentAction action)
+{
+ mAction = action;
- mNameLabel = new QLabel(tr("File Name:"), this);
+ ui.projectGroupBoxLayout->insertWidget (0, mAdjusterWidget);
- QRegExpValidator *validator = new QRegExpValidator(QRegExp("^[a-zA-Z0-9\\s]*$"));
- mNameLineEdit = new LineEdit(this);
- mNameLineEdit->setValidator(validator);
+ switch (mAction)
+ {
+ case ContentAction_New:
+ buildNewFileView();
+ break;
- nameLayout->addSpacerItem(spacer);
- nameLayout->addWidget(mNameLabel);
- nameLayout->addWidget(mNameLineEdit);
+ case ContentAction_Edit:
+ buildOpenFileView();
+ break;
- mButtonBox = new QDialogButtonBox(this);
+ default:
+ break;
+ }
- mCreateButton = new QPushButton(tr("Create"), this);
- mCreateButton->setEnabled(false);
+ mAdjusterWidget->setFilenameCheck (mAction == ContentAction_New);
- verticalLayout->addLayout(nameLayout);
- verticalLayout->addWidget(mButtonBox);
+ //connections common to both dialog view flavors
+ connect (mSelector, SIGNAL (signalCurrentGamefileIndexChanged (int)),
+ this, SLOT (slotUpdateAcceptButton (int)));
- // Set sizes
- QList<int> sizeList;
- sizeList << 175;
- sizeList << 200;
+ connect (ui.projectButtonBox, SIGNAL (rejected()), this, SLOT (slotRejected()));
- splitter->setSizes(sizeList);
+ show();
+ raise();
+ activateWindow();
+}
- resize(600, 400);
+void CSVDoc::FileDialog::buildNewFileView()
+{
+ setWindowTitle(tr("Create a new addon"));
- connect(mDataFilesModel, SIGNAL(layoutChanged()), this, SLOT(updateViews()));
- connect(mDataFilesModel, SIGNAL(checkedItemsChanged(QStringList)), this, SLOT(updateOpenButton(QStringList)));
- connect(mNameLineEdit, SIGNAL(textChanged(QString)), this, SLOT(updateCreateButton(QString)));
+ QPushButton* createButton = ui.projectButtonBox->button (QDialogButtonBox::Ok);
+ createButton->setText ("Create");
+ createButton->setEnabled (false);
- connect(filterLineEdit, SIGNAL(textChanged(QString)), this, SLOT(filterChanged(QString)));
+ mFileWidget = new FileWidget (this);
- connect(pluginsTable, SIGNAL(doubleClicked(QModelIndex)), this, SLOT(setCheckState(QModelIndex)));
- connect(mastersTable, SIGNAL(doubleClicked(QModelIndex)), this, SLOT(setCheckState(QModelIndex)));
+ mFileWidget->setType (true);
+ mFileWidget->extensionLabelIsVisible(true);
- connect(mCreateButton, SIGNAL(clicked()), this, SLOT(createButtonClicked()));
+ ui.projectGroupBoxLayout->insertWidget (0, mFileWidget);
- connect(mButtonBox, SIGNAL(accepted()), this, SLOT(accept()));
- connect(mButtonBox, SIGNAL(rejected()), this, SLOT(reject()));
-}
+ connect (mFileWidget, SIGNAL (nameChanged (const QString&, bool)),
+ mAdjusterWidget, SLOT (setName (const QString&, bool)));
-void FileDialog::updateViews()
-{
- // Ensure the columns are hidden because sort() re-enables them
- mastersTable->setColumnHidden(1, true);
- mastersTable->setColumnHidden(3, true);
- mastersTable->setColumnHidden(4, true);
- mastersTable->setColumnHidden(5, true);
- mastersTable->setColumnHidden(6, true);
- mastersTable->setColumnHidden(7, true);
- mastersTable->setColumnHidden(8, true);
- mastersTable->resizeColumnsToContents();
-
- pluginsTable->setColumnHidden(1, true);
- pluginsTable->setColumnHidden(3, true);
- pluginsTable->setColumnHidden(4, true);
- pluginsTable->setColumnHidden(5, true);
- pluginsTable->setColumnHidden(6, true);
- pluginsTable->setColumnHidden(7, true);
- pluginsTable->setColumnHidden(8, true);
- pluginsTable->resizeColumnsToContents();
+ connect (mFileWidget, SIGNAL (nameChanged(const QString &, bool)),
+ this, SLOT (slotUpdateAcceptButton(const QString &, bool)));
+ connect (ui.projectButtonBox, SIGNAL (accepted()), this, SLOT (slotNewFile()));
}
-void FileDialog::updateOpenButton(const QStringList &items)
+void CSVDoc::FileDialog::buildOpenFileView()
{
- QPushButton *openButton = mButtonBox->button(QDialogButtonBox::Open);
-
- if (!openButton)
- return;
+ setWindowTitle(tr("Open"));
+ ui.projectGroupBox->setTitle (QString(""));
- openButton->setEnabled(!items.isEmpty());
-}
+ ui.projectButtonBox->button(QDialogButtonBox::Ok)->setEnabled (false);
-void FileDialog::updateCreateButton(const QString &name)
-{
- if (!mCreateButton->isVisible())
- return;
+ connect (mSelector, SIGNAL (signalAddonFileSelected (int)), this, SLOT (slotUpdateAcceptButton (int)));
+ connect (mSelector, SIGNAL (signalAddonFileUnselected (int)), this, SLOT (slotUpdateAcceptButton (int)));
- mCreateButton->setEnabled(!name.isEmpty());
+ connect (ui.projectButtonBox, SIGNAL (accepted()), this, SLOT (slotOpenFile()));
}
-void FileDialog::filterChanged(const QString &filter)
+void CSVDoc::FileDialog::slotUpdateAcceptButton (int)
{
- QRegExp filterRe(filter, Qt::CaseInsensitive, QRegExp::FixedString);
- mFilterProxyModel->setFilterRegExp(filterRe);
-}
+ QString name = "";
-void FileDialog::addFiles(const QString &path)
-{
- mDataFilesModel->addFiles(path);
- mDataFilesModel->sort(3); // Sort by date accessed
-}
+ if (mAction == ContentAction_New)
+ name = mFileWidget->getName();
-void FileDialog::setEncoding(const QString &encoding)
-{
- mDataFilesModel->setEncoding(encoding);
+ slotUpdateAcceptButton (name, true);
}
-void FileDialog::setCheckState(QModelIndex index)
+void CSVDoc::FileDialog::slotUpdateAcceptButton(const QString &name, bool)
{
- if (!index.isValid())
- return;
-
- QObject *object = QObject::sender();
-
- // Not a signal-slot call
- if (!object)
- return;
+ bool success = (mSelector->selectedFiles().size() > 0);
+ bool isNew = (mAction == ContentAction_New);
- if (object->objectName() == QLatin1String("PluginsTable")) {
- QModelIndex sourceIndex = mPluginsProxyModel->mapToSource(
- mFilterProxyModel->mapToSource(index));
-
- if (sourceIndex.isValid()) {
- (mDataFilesModel->checkState(sourceIndex) == Qt::Checked)
- ? mDataFilesModel->setCheckState(sourceIndex, Qt::Unchecked)
- : mDataFilesModel->setCheckState(sourceIndex, Qt::Checked);
- }
+ if (isNew)
+ success = success && !(name.isEmpty());
+ else
+ {
+ ContentSelectorModel::EsmFile *file = mSelector->selectedFiles().back();
+ mAdjusterWidget->setName (file->filePath(), !file->isGameFile());
}
- if (object->objectName() == QLatin1String("MastersTable")) {
- QModelIndex sourceIndex = mMastersProxyModel->mapToSource(index);
-
- if (sourceIndex.isValid()) {
- (mDataFilesModel->checkState(sourceIndex) == Qt::Checked)
- ? mDataFilesModel->setCheckState(sourceIndex, Qt::Unchecked)
- : mDataFilesModel->setCheckState(sourceIndex, Qt::Checked);
- }
- }
-
- return;
+ ui.projectButtonBox->button (QDialogButtonBox::Ok)->setEnabled (success);
}
-QStringList FileDialog::checkedItemsPaths()
+QString CSVDoc::FileDialog::filename() const
{
- return mDataFilesModel->checkedItemsPaths();
-}
+ if (mAction == ContentAction_New)
+ return "";
-QString FileDialog::fileName()
-{
- return mNameLineEdit->text();
+ return mSelector->currentFile();
}
-void FileDialog::openFile()
+void CSVDoc::FileDialog::slotRejected()
{
- setWindowTitle(tr("Open"));
-
- mNameLabel->hide();
- mNameLineEdit->hide();
- mCreateButton->hide();
-
- mButtonBox->removeButton(mCreateButton);
- mButtonBox->setStandardButtons(QDialogButtonBox::Cancel | QDialogButtonBox::Open);
- QPushButton *openButton = mButtonBox->button(QDialogButtonBox::Open);
- openButton->setEnabled(false);
-
- show();
- raise();
- activateWindow();
+ emit rejected();
+ close();
}
-void FileDialog::newFile()
+void CSVDoc::FileDialog::slotNewFile()
{
- setWindowTitle(tr("New"));
-
- mNameLabel->show();
- mNameLineEdit->clear();
- mNameLineEdit->show();
- mCreateButton->show();
-
- mButtonBox->setStandardButtons(QDialogButtonBox::Cancel);
- mButtonBox->addButton(mCreateButton, QDialogButtonBox::ActionRole);
-
- show();
- raise();
- activateWindow();
+ emit signalCreateNewFile (mAdjusterWidget->getPath());
}
-void FileDialog::accept()
+void CSVDoc::FileDialog::slotOpenFile()
{
- emit openFiles();
-}
+ ContentSelectorModel::EsmFile *file = mSelector->selectedFiles().back();
-void FileDialog::createButtonClicked()
-{
- emit createNewFile();
+ mAdjusterWidget->setName (file->filePath(), !file->isGameFile());
+
+ emit signalOpenFiles (mAdjusterWidget->getPath());
}
diff --git a/apps/opencs/view/doc/filedialog.hpp b/apps/opencs/view/doc/filedialog.hpp
index b21618d5de..d9fd569435 100644
--- a/apps/opencs/view/doc/filedialog.hpp
+++ b/apps/opencs/view/doc/filedialog.hpp
@@ -4,63 +4,71 @@
#include <QDialog>
#include <QModelIndex>
-#include "ui_datafilespage.h"
+#include <boost/filesystem/path.hpp>
+#include "adjusterwidget.hpp"
-class QDialogButtonBox;
-class QSortFilterProxyModel;
-class QAbstractItemModel;
-class QPushButton;
-class QStringList;
-class QString;
-class QMenu;
+#ifndef CS_QT_BOOST_FILESYSTEM_PATH_DECLARED
+#define CS_QT_BOOST_FILESYSTEM_PATH_DECLARED
+Q_DECLARE_METATYPE (boost::filesystem::path)
+#endif
+
+#include "ui_filedialog.h"
class DataFilesModel;
class PluginsProxyModel;
-class FileDialog : public QDialog, private Ui::DataFilesPage
+namespace ContentSelectorView
+{
+ class ContentSelector;
+}
+
+namespace CSVDoc
{
- Q_OBJECT
-public:
- explicit FileDialog(QWidget *parent = 0);
- void addFiles(const QString &path);
- void setEncoding(const QString &encoding);
+ class FileWidget;
+
+ class FileDialog : public QDialog
+ {
+ Q_OBJECT
+
+ private:
+
+ ContentSelectorView::ContentSelector *mSelector;
+ Ui::FileDialog ui;
+ ContentAction mAction;
+ FileWidget *mFileWidget;
+ AdjusterWidget *mAdjusterWidget;
+
+ public:
- void openFile();
- void newFile();
- void accepted();
+ explicit FileDialog(QWidget *parent = 0);
+ void showDialog (ContentAction action);
- QStringList checkedItemsPaths();
- QString fileName();
+ void addFiles (const QString &path);
-signals:
- void openFiles();
- void createNewFile();
-
-public slots:
- void accept();
+ QString filename() const;
+ QStringList selectedFilePaths();
-private slots:
- void updateViews();
- void updateOpenButton(const QStringList &items);
- void updateCreateButton(const QString &name);
- void setCheckState(QModelIndex index);
+ void setLocalData (const boost::filesystem::path& localData);
- void filterChanged(const QString &filter);
+ private:
- void createButtonClicked();
+ void buildNewFileView();
+ void buildOpenFileView();
-private:
- QLabel *mNameLabel;
- LineEdit *mNameLineEdit;
+ signals:
- QPushButton *mCreateButton;
- QDialogButtonBox *mButtonBox;
+ void signalOpenFiles (const boost::filesystem::path &path);
+ void signalCreateNewFile (const boost::filesystem::path &path);
- DataFilesModel *mDataFilesModel;
+ void signalUpdateAcceptButton (bool, int);
- PluginsProxyModel *mPluginsProxyModel;
- QSortFilterProxyModel *mMastersProxyModel;
- QSortFilterProxyModel *mFilterProxyModel;
-};
+ private slots:
+ void slotNewFile();
+ void slotOpenFile();
+ void slotUpdateAcceptButton (int);
+ void slotUpdateAcceptButton (const QString &, bool);
+ void slotRejected();
+ };
+}
#endif // FILEDIALOG_HPP
diff --git a/apps/opencs/view/doc/filewidget.cpp b/apps/opencs/view/doc/filewidget.cpp
new file mode 100644
index 0000000000..9cd2fad422
--- /dev/null
+++ b/apps/opencs/view/doc/filewidget.cpp
@@ -0,0 +1,58 @@
+
+#include "filewidget.hpp"
+
+#include <QHBoxLayout>
+#include <QLineEdit>
+#include <QLabel>
+#include <QRegExpValidator>
+#include <QRegExp>
+
+QString CSVDoc::FileWidget::getExtension() const
+{
+ return mAddon ? ".omwaddon" : ".omwgame";
+}
+
+CSVDoc::FileWidget::FileWidget (QWidget *parent) : QWidget (parent), mAddon (false)
+{
+ QHBoxLayout *layout = new QHBoxLayout (this);
+
+ mInput = new QLineEdit (this);
+ mInput->setValidator (new QRegExpValidator(QRegExp("^[a-zA-Z0-9\\s]*$")));
+
+ layout->addWidget (mInput, 1);
+
+ mType = new QLabel (this);
+
+ layout ->addWidget (mType);
+
+ connect (mInput, SIGNAL (textChanged (const QString&)), this, SLOT (textChanged (const QString&)));
+
+ setLayout (layout);
+}
+
+void CSVDoc::FileWidget::setType (bool addon)
+{
+ mAddon = addon;
+
+ mType->setText (getExtension());
+}
+
+QString CSVDoc::FileWidget::getName() const
+{
+ QString text = mInput->text();
+
+ if (text.isEmpty())
+ return "";
+
+ return text + getExtension();
+}
+
+void CSVDoc::FileWidget::textChanged (const QString& text)
+{
+ emit nameChanged (getName(), mAddon);
+}
+
+void CSVDoc::FileWidget::extensionLabelIsVisible(bool visible)
+{
+ mType->setVisible(visible);
+}
diff --git a/apps/opencs/view/doc/filewidget.hpp b/apps/opencs/view/doc/filewidget.hpp
new file mode 100644
index 0000000000..ff09d71a39
--- /dev/null
+++ b/apps/opencs/view/doc/filewidget.hpp
@@ -0,0 +1,42 @@
+#ifndef CSV_DOC_FILEWIDGET_H
+#define CSV_DOC_FILEWIDGET_H
+
+#include <QWidget>
+
+class QLabel;
+class QString;
+class QLineEdit;
+
+namespace CSVDoc
+{
+ class FileWidget : public QWidget
+ {
+ Q_OBJECT
+
+ bool mAddon;
+ QLineEdit *mInput;
+ QLabel *mType;
+
+ QString getExtension() const;
+
+ public:
+
+ FileWidget (QWidget *parent = 0);
+
+ void setType (bool addon);
+
+ QString getName() const;
+
+ void extensionLabelIsVisible(bool visible);
+
+ private slots:
+
+ void textChanged (const QString& text);
+
+ signals:
+
+ void nameChanged (const QString& file, bool addon);
+ };
+}
+
+#endif
diff --git a/apps/opencs/view/doc/newgame.cpp b/apps/opencs/view/doc/newgame.cpp
new file mode 100644
index 0000000000..98681c499d
--- /dev/null
+++ b/apps/opencs/view/doc/newgame.cpp
@@ -0,0 +1,68 @@
+
+#include "newgame.hpp"
+
+#include <QApplication>
+#include <QDesktopWidget>
+#include <QVBoxLayout>
+#include <QDialogButtonBox>
+#include <QPushButton>
+
+#include "filewidget.hpp"
+#include "adjusterwidget.hpp"
+
+CSVDoc::NewGameDialogue::NewGameDialogue()
+{
+ setWindowTitle ("Create New Game");
+
+ QVBoxLayout *layout = new QVBoxLayout (this);
+
+ mFileWidget = new FileWidget (this);
+ mFileWidget->setType (false);
+
+ layout->addWidget (mFileWidget, 1);
+
+ mAdjusterWidget = new AdjusterWidget (this);
+
+ layout->addWidget (mAdjusterWidget, 1);
+
+ QDialogButtonBox *buttons = new QDialogButtonBox (this);
+
+ mCreate = new QPushButton ("Create", this);
+ mCreate->setDefault (true);
+ mCreate->setEnabled (false);
+
+ buttons->addButton (mCreate, QDialogButtonBox::AcceptRole);
+
+ QPushButton *cancel = new QPushButton ("Cancel", this);
+
+ buttons->addButton (cancel, QDialogButtonBox::RejectRole);
+
+ layout->addWidget (buttons);
+
+ setLayout (layout);
+
+ connect (mAdjusterWidget, SIGNAL (stateChanged (bool)), this, SLOT (stateChanged (bool)));
+ connect (mCreate, SIGNAL (clicked()), this, SLOT (create()));
+ connect (cancel, SIGNAL (clicked()), this, SLOT (reject()));
+ connect (mFileWidget, SIGNAL (nameChanged (const QString&, bool)),
+ mAdjusterWidget, SLOT (setName (const QString&, bool)));
+
+ QRect scr = QApplication::desktop()->screenGeometry();
+ QRect rect = geometry();
+ move (scr.center().x() - rect.center().x(), scr.center().y() - rect.center().y());
+}
+
+void CSVDoc::NewGameDialogue::setLocalData (const boost::filesystem::path& localData)
+{
+ mAdjusterWidget->setLocalData (localData);
+}
+
+void CSVDoc::NewGameDialogue::stateChanged (bool valid)
+{
+ mCreate->setEnabled (valid);
+}
+
+void CSVDoc::NewGameDialogue::create()
+{
+ emit createRequest (mAdjusterWidget->getPath());
+}
diff --git a/apps/opencs/view/doc/newgame.hpp b/apps/opencs/view/doc/newgame.hpp
new file mode 100644
index 0000000000..9ad7ea1690
--- /dev/null
+++ b/apps/opencs/view/doc/newgame.hpp
@@ -0,0 +1,47 @@
+#ifndef CSV_DOC_NEWGAME_H
+#define CSV_DOC_NEWGAME_H
+
+#include <boost/filesystem/path.hpp>
+
+#include <QDialog>
+#include <QMetaType>
+
+#ifndef CS_QT_BOOST_FILESYSTEM_PATH_DECLARED
+#define CS_QT_BOOST_FILESYSTEM_PATH_DECLARED
+Q_DECLARE_METATYPE (boost::filesystem::path)
+#endif
+
+class QPushButton;
+
+namespace CSVDoc
+{
+ class FileWidget;
+ class AdjusterWidget;
+
+ class NewGameDialogue : public QDialog
+ {
+ Q_OBJECT
+
+ QPushButton *mCreate;
+ FileWidget *mFileWidget;
+ AdjusterWidget *mAdjusterWidget;
+
+ public:
+
+ NewGameDialogue();
+
+ void setLocalData (const boost::filesystem::path& localData);
+
+ signals:
+
+ void createRequest (const boost::filesystem::path& file);
+
+ private slots:
+
+ void stateChanged (bool valid);
+
+ void create();
+ };
+}
+
+#endif
diff --git a/apps/opencs/view/doc/startup.cpp b/apps/opencs/view/doc/startup.cpp
index 6c1e740589..5d59492c64 100644
--- a/apps/opencs/view/doc/startup.cpp
+++ b/apps/opencs/view/doc/startup.cpp
@@ -3,21 +3,117 @@
#include <QApplication>
#include <QDesktopWidget>
-#include <QPushButton>
+#include <QVBoxLayout>
#include <QHBoxLayout>
#include <QRect>
+#include <QGridLayout>
+#include <QLabel>
+#include <QIcon>
+#include <QPushButton>
+
+QPushButton *CSVDoc::StartupDialogue::addButton (const QString& label, const QIcon& icon)
+{
+ int column = mColumn--;
+
+ QPushButton *button = new QPushButton (this);
+
+ button->setIcon (QIcon (icon));
+
+ button->setSizePolicy (QSizePolicy (QSizePolicy::Preferred, QSizePolicy::Preferred));
+
+ mLayout->addWidget (button, 0, column);
+
+ mLayout->addWidget (new QLabel (label, this), 1, column, Qt::AlignCenter);
+
+ int width = mLayout->itemAtPosition (1, column)->widget()->sizeHint().width();
+
+ if (width>mWidth)
+ mWidth = width;
-CSVDoc::StartupDialogue::StartupDialogue()
+ return button;
+}
+
+
+QWidget *CSVDoc::StartupDialogue::createButtons()
{
- QHBoxLayout *layout = new QHBoxLayout (this);
+ QWidget *widget = new QWidget (this);
- QPushButton *createDocument = new QPushButton ("new", this);
- connect (createDocument, SIGNAL (clicked()), this, SIGNAL (createDocument()));
- layout->addWidget (createDocument);
+ mLayout = new QGridLayout (widget);
- QPushButton *loadDocument = new QPushButton ("load", this);
+ /// \todo add icons
+ QPushButton *loadDocument = addButton ("Edit A Content File", QIcon (":startup/edit-content"));
connect (loadDocument, SIGNAL (clicked()), this, SIGNAL (loadDocument()));
- layout->addWidget (loadDocument);
+
+ QPushButton *createAddon = addButton ("Create A New Addon", QIcon (":startup/create-addon"));
+ connect (createAddon, SIGNAL (clicked()), this, SIGNAL (createAddon()));
+
+ QPushButton *createGame = addButton ("Create A New Game", QIcon (":startup/create-game"));
+ connect (createGame, SIGNAL (clicked()), this, SIGNAL (createGame()));
+
+ for (int i=0; i<3; ++i)
+ mLayout->setColumnMinimumWidth (i, mWidth);
+
+ mLayout->setRowMinimumHeight (0, mWidth);
+
+ mLayout->setSizeConstraint (QLayout::SetMinimumSize);
+ mLayout->setHorizontalSpacing (32);
+
+ mLayout->setContentsMargins (16, 16, 16, 8);
+
+ loadDocument->setIconSize (QSize (mWidth, mWidth));
+ createGame->setIconSize (QSize (mWidth, mWidth));
+ createAddon->setIconSize (QSize (mWidth, mWidth));
+
+ widget->setLayout (mLayout);
+
+ return widget;
+}
+
+QWidget *CSVDoc::StartupDialogue::createTools()
+{
+ QWidget *widget = new QWidget (this);
+
+ QHBoxLayout *layout = new QHBoxLayout (widget);
+ layout->setDirection (QBoxLayout::RightToLeft);
+ layout->setContentsMargins (4, 4, 4, 4);
+
+ QPushButton *config = new QPushButton (widget);
+
+ config->setSizePolicy (QSizePolicy (QSizePolicy::Fixed, QSizePolicy::Fixed));
+ config->setIcon (QIcon (":startup/configure"));
+
+ layout->addWidget (config);
+
+ layout->addWidget (new QWidget, 1); // dummy widget; stops buttons from taking all the space
+
+ widget->setLayout (layout);
+
+ connect (config, SIGNAL (clicked()), this, SIGNAL (editConfig()));
+
+ return widget;
+}
+
+CSVDoc::StartupDialogue::StartupDialogue() : mWidth (0), mColumn (2)
+{
+ setWindowTitle ("Open CS");
+
+ QVBoxLayout *layout = new QVBoxLayout (this);
+
+ layout->setContentsMargins (0, 0, 0, 0);
+
+ layout->addWidget (createButtons());
+ layout->addWidget (createTools());
+
+ /// \todo remove this label once loading and saving are fully implemented
+ QLabel *warning = new QLabel ("<font color=Red>WARNING:<p>OpenCS is in alpha stage.<br>The code for loading and saving is incomplete.<br>This version of OpenCS is only a preview.<br>Do NOT use it for real editing!<br>You will lose records both on loading and on saving.<p>Please note:<br>If you lose data and come to the OpenMW forum to complain,<br>we will mock you.</font color>");
+
+ QFont font;
+ font.setPointSize (12);
+ font.setBold (true);
+
+ warning->setFont (font);
+
+ layout->addWidget (warning, 1);
setLayout (layout);
diff --git a/apps/opencs/view/doc/startup.hpp b/apps/opencs/view/doc/startup.hpp
index f24d2a64ba..f059a44e5c 100644
--- a/apps/opencs/view/doc/startup.hpp
+++ b/apps/opencs/view/doc/startup.hpp
@@ -3,21 +3,43 @@
#include <QWidget>
+class QGridLayout;
+class QString;
+class QPushButton;
+class QWidget;
+class QIcon;
+
namespace CSVDoc
{
class StartupDialogue : public QWidget
{
Q_OBJECT
+ private:
+
+ int mWidth;
+ int mColumn;
+ QGridLayout *mLayout;
+
+ QPushButton *addButton (const QString& label, const QIcon& icon);
+
+ QWidget *createButtons();
+
+ QWidget *createTools();
+
public:
StartupDialogue();
signals:
- void createDocument();
+ void createGame();
+
+ void createAddon();
void loadDocument();
+
+ void editConfig();
};
}
diff --git a/apps/opencs/view/doc/view.cpp b/apps/opencs/view/doc/view.cpp
index 6801ea20df..5713449f23 100644
--- a/apps/opencs/view/doc/view.cpp
+++ b/apps/opencs/view/doc/view.cpp
@@ -27,9 +27,13 @@ void CSVDoc::View::setupFileMenu()
{
QMenu *file = menuBar()->addMenu (tr ("&File"));
- QAction *new_ = new QAction (tr ("New"), this);
- connect (new_, SIGNAL (triggered()), this, SIGNAL (newDocumentRequest()));
- file->addAction (new_);
+ QAction *newGame = new QAction (tr ("New Game"), this);
+ connect (newGame, SIGNAL (triggered()), this, SIGNAL (newGameRequest()));
+ file->addAction (newGame);
+
+ QAction *newAddon = new QAction (tr ("New Addon"), this);
+ connect (newAddon, SIGNAL (triggered()), this, SIGNAL (newAddonRequest()));
+ file->addAction (newAddon);
QAction *open = new QAction (tr ("&Open"), this);
connect (open, SIGNAL (triggered()), this, SIGNAL (loadDocumentRequest()));
@@ -67,7 +71,7 @@ void CSVDoc::View::setupEditMenu()
edit->addAction (mRedo);
QAction *userSettings = new QAction (tr ("&Preferences"), this);
- connect (userSettings, SIGNAL (triggered()), this, SLOT (showUserSettings()));
+ connect (userSettings, SIGNAL (triggered()), this, SIGNAL (editSettingsRequest()));
edit->addAction (userSettings);
}
@@ -111,6 +115,10 @@ void CSVDoc::View::setupWorldMenu()
world->addSeparator(); // items that don't represent single record lists follow here
+ QAction *scene = new QAction (tr ("Scene"), this);
+ connect (scene, SIGNAL (triggered()), this, SLOT (addSceneSubView()));
+ world->addAction (scene);
+
QAction *regionMap = new QAction (tr ("Region Map"), this);
connect (regionMap, SIGNAL (triggered()), this, SLOT (addRegionMapSubView()));
world->addAction (regionMap);
@@ -155,6 +163,14 @@ void CSVDoc::View::setupMechanicsMenu()
QAction *spells = new QAction (tr ("Spells"), this);
connect (spells, SIGNAL (triggered()), this, SLOT (addSpellsSubView()));
mechanics->addAction (spells);
+
+ QAction *topics = new QAction (tr ("Topics"), this);
+ connect (topics, SIGNAL (triggered()), this, SLOT (addTopicsSubView()));
+ mechanics->addAction (topics);
+
+ QAction *journals = new QAction (tr ("Journals"), this);
+ connect (journals, SIGNAL (triggered()), this, SLOT (addJournalsSubView()));
+ mechanics->addAction (journals);
}
void CSVDoc::View::setupAssetsMenu()
@@ -180,7 +196,7 @@ void CSVDoc::View::updateTitle()
{
std::ostringstream stream;
- stream << mDocument->getName();
+ stream << mDocument->getSavePath().filename().string();
if (mDocument->getState() & CSMDoc::State_Modified)
stream << " *";
@@ -399,6 +415,21 @@ void CSVDoc::View::addFiltersSubView()
addSubView (CSMWorld::UniversalId::Type_Filters);
}
+void CSVDoc::View::addSceneSubView()
+{
+ addSubView (CSMWorld::UniversalId::Type_Scene);
+}
+
+void CSVDoc::View::addTopicsSubView()
+{
+ addSubView (CSMWorld::UniversalId::Type_Topics);
+}
+
+void CSVDoc::View::addJournalsSubView()
+{
+ addSubView (CSMWorld::UniversalId::Type_Journals);
+}
+
void CSVDoc::View::abortOperation (int type)
{
mDocument->abortOperation (type);
@@ -415,13 +446,6 @@ void CSVDoc::View::exit()
emit exitApplicationRequest (this);
}
-void CSVDoc::View::showUserSettings()
-{
- CSVSettings::UserSettingsDialog *settingsDialog = new CSVSettings::UserSettingsDialog(this);
-
- settingsDialog->show();
-}
-
void CSVDoc::View::resizeViewWidth (int width)
{
if (width >= 0)
diff --git a/apps/opencs/view/doc/view.hpp b/apps/opencs/view/doc/view.hpp
index 56c0b3edd4..2a31d9d807 100644
--- a/apps/opencs/view/doc/view.hpp
+++ b/apps/opencs/view/doc/view.hpp
@@ -106,12 +106,16 @@ namespace CSVDoc
signals:
- void newDocumentRequest();
+ void newGameRequest();
+
+ void newAddonRequest();
void loadDocumentRequest();
void exitApplicationRequest (CSVDoc::View *view);
+ void editSettingsRequest();
+
public slots:
void addSubView (const CSMWorld::UniversalId& id);
@@ -160,7 +164,11 @@ namespace CSVDoc
void addFiltersSubView();
- void showUserSettings();
+ void addSceneSubView();
+
+ void addTopicsSubView();
+
+ void addJournalsSubView();
void toggleShowStatusBar (bool show);
};
diff --git a/apps/opencs/view/doc/viewmanager.cpp b/apps/opencs/view/doc/viewmanager.cpp
index 6d06e42488..a4849795b2 100644
--- a/apps/opencs/view/doc/viewmanager.cpp
+++ b/apps/opencs/view/doc/viewmanager.cpp
@@ -8,12 +8,13 @@
#include "../../model/doc/documentmanager.hpp"
#include "../../model/doc/document.hpp"
+#include "../../model/world/columns.hpp"
#include "../world/util.hpp"
#include "../world/enumdelegate.hpp"
#include "../world/vartypedelegate.hpp"
#include "../world/recordstatusdelegate.hpp"
-#include "../world/refidtypedelegate.hpp"
+#include "../world/idtypedelegate.hpp"
#include "../settings/usersettingsdialog.hpp"
#include "view.hpp"
@@ -43,51 +44,6 @@ void CSVDoc::ViewManager::updateIndices()
CSVDoc::ViewManager::ViewManager (CSMDoc::DocumentManager& documentManager)
: mDocumentManager (documentManager), mExitOnSaveStateChange(false), mUserWarned(false)
{
- static const char *sSpecialisations[] =
- {
- "Combat", "Magic", "Stealth", 0
- };
-
- static const char *sAttributes[] =
- {
- "Strength", "Intelligence", "Willpower", "Agility", "Speed", "Endurance", "Personality",
- "Luck", 0
- };
-
- static const char *sSpellTypes[] =
- {
- "Spell", "Ability", "Blight", "Disease", "Curse", "Power", 0
- };
-
- static const char *sApparatusTypes[] =
- {
- "Mortar & Pestle", "Albemic", "Calcinator", "Retort", 0
- };
-
- static const char *sArmorTypes[] =
- {
- "Helmet", "Cuirass", "Left Pauldron", "Right Pauldron", "Greaves", "Boots", "Left Gauntlet",
- "Right Gauntlet", "Shield", "Left Bracer", "Right Bracer", 0
- };
-
- static const char *sClothingTypes[] =
- {
- "Pants", "Shoes", "Shirt", "Belt", "Robe", "Right Glove", "Left Glove", "Skirt", "Ring",
- "Amulet", 0
- };
-
- static const char *sCreatureTypes[] =
- {
- "Creature", "Deadra", "Undead", "Humanoid", 0
- };
-
- static const char *sWeaponTypes[] =
- {
- "Short Blade 1H", "Long Blade 1H", "Long Blade 2H", "Blunt 1H", "Blunt 2H Close",
- "Blunt 2H Wide", "Spear 2H", "Axe 1H", "Axe 2H", "Bow", "Crossbow", "Thrown", "Arrow",
- "Bolt", 0
- };
-
mDelegateFactories = new CSVWorld::CommandDelegateFactoryCollection;
mDelegateFactories->add (CSMWorld::ColumnBase::Display_GmstVarType,
@@ -96,38 +52,38 @@ CSVDoc::ViewManager::ViewManager (CSMDoc::DocumentManager& documentManager)
mDelegateFactories->add (CSMWorld::ColumnBase::Display_GlobalVarType,
new CSVWorld::VarTypeDelegateFactory (ESM::VT_Short, ESM::VT_Long, ESM::VT_Float));
- mDelegateFactories->add (CSMWorld::ColumnBase::Display_Specialisation,
- new CSVWorld::EnumDelegateFactory (sSpecialisations));
-
- mDelegateFactories->add (CSMWorld::ColumnBase::Display_Attribute,
- new CSVWorld::EnumDelegateFactory (sAttributes, true));
-
- mDelegateFactories->add (CSMWorld::ColumnBase::Display_SpellType,
- new CSVWorld::EnumDelegateFactory (sSpellTypes));
-
- mDelegateFactories->add (CSMWorld::ColumnBase::Display_ApparatusType,
- new CSVWorld::EnumDelegateFactory (sApparatusTypes));
-
- mDelegateFactories->add (CSMWorld::ColumnBase::Display_ArmorType,
- new CSVWorld::EnumDelegateFactory (sArmorTypes));
-
- mDelegateFactories->add (CSMWorld::ColumnBase::Display_ClothingType,
- new CSVWorld::EnumDelegateFactory (sClothingTypes));
+ mDelegateFactories->add (CSMWorld::ColumnBase::Display_RecordState,
+ new CSVWorld::RecordStatusDelegateFactory());
- mDelegateFactories->add (CSMWorld::ColumnBase::Display_CreatureType,
- new CSVWorld::EnumDelegateFactory (sCreatureTypes));
+ mDelegateFactories->add (CSMWorld::ColumnBase::Display_RefRecordType,
+ new CSVWorld::IdTypeDelegateFactory());
- mDelegateFactories->add (CSMWorld::ColumnBase::Display_WeaponType,
- new CSVWorld::EnumDelegateFactory (sWeaponTypes));
+ struct Mapping
+ {
+ CSMWorld::ColumnBase::Display mDisplay;
+ CSMWorld::Columns::ColumnId mColumnId;
+ bool mAllowNone;
+ };
- mDelegateFactories->add (CSMWorld::ColumnBase::Display_RecordState,
- new CSVWorld::RecordStatusDelegateFactory() );
+ static const Mapping sMapping[] =
+ {
+ { CSMWorld::ColumnBase::Display_Specialisation, CSMWorld::Columns::ColumnId_Specialisation, false },
+ { CSMWorld::ColumnBase::Display_Attribute, CSMWorld::Columns::ColumnId_Attribute, true },
+ { CSMWorld::ColumnBase::Display_SpellType, CSMWorld::Columns::ColumnId_SpellType, false },
+ { CSMWorld::ColumnBase::Display_ApparatusType, CSMWorld::Columns::ColumnId_ApparatusType, false },
+ { CSMWorld::ColumnBase::Display_ArmorType, CSMWorld::Columns::ColumnId_ArmorType, false },
+ { CSMWorld::ColumnBase::Display_ClothingType, CSMWorld::Columns::ColumnId_ClothingType, false },
+ { CSMWorld::ColumnBase::Display_CreatureType, CSMWorld::Columns::ColumnId_CreatureType, false },
+ { CSMWorld::ColumnBase::Display_WeaponType, CSMWorld::Columns::ColumnId_WeaponType, false },
+ { CSMWorld::ColumnBase::Display_DialogueType, CSMWorld::Columns::ColumnId_DialogueType, false }
+ };
- mDelegateFactories->add (CSMWorld::ColumnBase::Display_RefRecordType,
- new CSVWorld::RefIdTypeDelegateFactory() );
+ for (std::size_t i=0; i<sizeof (sMapping)/sizeof (Mapping); ++i)
+ mDelegateFactories->add (sMapping[i].mDisplay, new CSVWorld::EnumDelegateFactory (
+ CSMWorld::Columns::getEnums (sMapping[i].mColumnId), sMapping[i].mAllowNone));
connect (&CSMSettings::UserSettings::instance(), SIGNAL (signalUpdateEditorSetting (const QString &, const QString &)),
- this, SLOT (slotUpdateEditorSetting (const QString &, const QString &)));
+ this, SLOT (slotUpdateEditorSetting (const QString &, const QString &)));
}
CSVDoc::ViewManager::~ViewManager()
@@ -152,13 +108,14 @@ CSVDoc::View *CSVDoc::ViewManager::addView (CSMDoc::Document *document)
View *view = new View (*this, document, countViews (document)+1);
-
mViews.push_back (view);
view->show();
- connect (view, SIGNAL (newDocumentRequest ()), this, SIGNAL (newDocumentRequest()));
+ connect (view, SIGNAL (newGameRequest ()), this, SIGNAL (newGameRequest()));
+ connect (view, SIGNAL (newAddonRequest ()), this, SIGNAL (newAddonRequest()));
connect (view, SIGNAL (loadDocumentRequest ()), this, SIGNAL (loadDocumentRequest()));
+ connect (view, SIGNAL (editSettingsRequest()), this, SIGNAL (editSettingsRequest()));
updateIndices();
diff --git a/apps/opencs/view/doc/viewmanager.hpp b/apps/opencs/view/doc/viewmanager.hpp
index 1f4dcd51b1..01f4951864 100644
--- a/apps/opencs/view/doc/viewmanager.hpp
+++ b/apps/opencs/view/doc/viewmanager.hpp
@@ -55,12 +55,16 @@ namespace CSVDoc
signals:
- void newDocumentRequest();
+ void newGameRequest();
+
+ void newAddonRequest();
void loadDocumentRequest();
void closeMessageBox();
+ void editSettingsRequest();
+
public slots:
void exitApplication (CSVDoc::View *view);
diff --git a/apps/opencs/view/filter/filtercreator.cpp b/apps/opencs/view/filter/filtercreator.cpp
index 47925ea57a..640c9fe785 100644
--- a/apps/opencs/view/filter/filtercreator.cpp
+++ b/apps/opencs/view/filter/filtercreator.cpp
@@ -6,6 +6,11 @@
#include "../../model/filter/filter.hpp"
+#include "../../model/world/data.hpp"
+#include "../../model/world/commands.hpp"
+#include "../../model/world/columns.hpp"
+#include "../../model/world/idtable.hpp"
+
std::string CSVFilter::FilterCreator::getNamespace() const
{
switch (mScope->currentIndex())
@@ -28,6 +33,15 @@ std::string CSVFilter::FilterCreator::getId() const
return getNamespace() + GenericCreator::getId();
}
+void CSVFilter::FilterCreator::configureCreateCommand (CSMWorld::CreateCommand& command) const
+{
+ int index =
+ dynamic_cast<CSMWorld::IdTable&> (*getData().getTableModel (getCollectionId())).
+ findColumnIndex (CSMWorld::Columns::ColumnId_Scope);
+
+ command.addValue (index, mScope->currentIndex());
+}
+
CSVFilter::FilterCreator::FilterCreator (CSMWorld::Data& data, QUndoStack& undoStack,
const CSMWorld::UniversalId& id)
: GenericCreator (data, undoStack, id)
@@ -39,7 +53,7 @@ CSVFilter::FilterCreator::FilterCreator (CSMWorld::Data& data, QUndoStack& undoS
mScope->addItem ("Project");
mScope->addItem ("Session");
- /// \ŧodo re-enable for OpenMW 1.1
+ /// \todo re-enable for OpenMW 1.1
// mScope->addItem ("Content");
connect (mScope, SIGNAL (currentIndexChanged (int)), this, SLOT (setScope (int)));
diff --git a/apps/opencs/view/filter/filtercreator.hpp b/apps/opencs/view/filter/filtercreator.hpp
index 82d38d22c7..437d01c8da 100644
--- a/apps/opencs/view/filter/filtercreator.hpp
+++ b/apps/opencs/view/filter/filtercreator.hpp
@@ -25,6 +25,8 @@ namespace CSVFilter
virtual std::string getId() const;
+ virtual void configureCreateCommand (CSMWorld::CreateCommand& command) const;
+
public:
FilterCreator (CSMWorld::Data& data, QUndoStack& undoStack,
diff --git a/apps/opencs/view/settings/usersettingsdialog.cpp b/apps/opencs/view/settings/usersettingsdialog.cpp
index 21311c2dab..e73e24dcb4 100644
--- a/apps/opencs/view/settings/usersettingsdialog.cpp
+++ b/apps/opencs/view/settings/usersettingsdialog.cpp
@@ -1,5 +1,7 @@
#include "usersettingsdialog.hpp"
+#include <boost/filesystem/path.hpp>
+
#include <QApplication>
#include <QDesktopWidget>
#include <QWidget>
@@ -9,14 +11,14 @@
#include <QFile>
#include <QPushButton>
#include <QDockWidget>
-
#include <QGridLayout>
+#include <QApplication>
+#include <QDesktopWidget>
+
+#include "../../model/settings/support.hpp"
#include "datadisplayformatpage.hpp"
#include "windowpage.hpp"
-
-#include "../../model/settings/support.hpp"
-#include <boost/filesystem/path.hpp>
#include "settingwidget.hpp"
CSVSettings::UserSettingsDialog::UserSettingsDialog(QMainWindow *parent) :
@@ -29,7 +31,11 @@ CSVSettings::UserSettingsDialog::UserSettingsDialog(QMainWindow *parent) :
connect (mListWidget,
SIGNAL (currentItemChanged(QListWidgetItem*, QListWidgetItem*)),
this,
- SLOT (slotChangePage (QListWidgetItem*, QListWidgetItem*)));
+ SLOT (slotChangePage (QListWidgetItem*, QListWidgetItem*)));
+
+ QRect scr = QApplication::desktop()->screenGeometry();
+ QRect rect = geometry();
+ move (scr.center().x() - rect.center().x(), scr.center().y() - rect.center().y());
}
CSVSettings::UserSettingsDialog::~UserSettingsDialog()
diff --git a/apps/opencs/view/tools/reportsubview.cpp b/apps/opencs/view/tools/reportsubview.cpp
index fe1be85d79..182d1cdd6c 100644
--- a/apps/opencs/view/tools/reportsubview.cpp
+++ b/apps/opencs/view/tools/reportsubview.cpp
@@ -6,6 +6,8 @@
#include "../../model/tools/reportmodel.hpp"
+#include "../../view/world/idtypedelegate.hpp"
+
CSVTools::ReportSubView::ReportSubView (const CSMWorld::UniversalId& id, CSMDoc::Document& document)
: CSVDoc::SubView (id), mModel (document.getReport (id))
{
@@ -18,6 +20,11 @@ CSVTools::ReportSubView::ReportSubView (const CSMWorld::UniversalId& id, CSMDoc:
mTable->setSelectionBehavior (QAbstractItemView::SelectRows);
mTable->setSelectionMode (QAbstractItemView::ExtendedSelection);
+ mIdTypeDelegate = CSVWorld::IdTypeDelegateFactory().makeDelegate (
+ document.getUndoStack(), this);
+
+ mTable->setItemDelegateForColumn (0, mIdTypeDelegate);
+
connect (mTable, SIGNAL (doubleClicked (const QModelIndex&)), this, SLOT (show (const QModelIndex&)));
}
@@ -26,6 +33,11 @@ void CSVTools::ReportSubView::setEditLock (bool locked)
// ignored. We don't change document state anyway.
}
+void CSVTools::ReportSubView::updateEditorSetting (const QString& key, const QString& value)
+{
+ mIdTypeDelegate->updateEditorSetting (key, value);
+}
+
void CSVTools::ReportSubView::show (const QModelIndex& index)
{
focusId (mModel->getUniversalId (index.row()));
diff --git a/apps/opencs/view/tools/reportsubview.hpp b/apps/opencs/view/tools/reportsubview.hpp
index 626ceb663d..6503ebd278 100644
--- a/apps/opencs/view/tools/reportsubview.hpp
+++ b/apps/opencs/view/tools/reportsubview.hpp
@@ -16,6 +16,11 @@ namespace CSMTools
class ReportModel;
}
+namespace CSVWorld
+{
+ class CommandDelegate;
+}
+
namespace CSVTools
{
class Table;
@@ -26,6 +31,7 @@ namespace CSVTools
CSMTools::ReportModel *mModel;
QTableView *mTable;
+ CSVWorld::CommandDelegate *mIdTypeDelegate;
public:
@@ -33,6 +39,8 @@ namespace CSVTools
virtual void setEditLock (bool locked);
+ virtual void updateEditorSetting (const QString&, const QString&);
+
private slots:
void show (const QModelIndex& index);
diff --git a/apps/opencs/view/world/dialoguecreator.cpp b/apps/opencs/view/world/dialoguecreator.cpp
new file mode 100644
index 0000000000..c16214283e
--- /dev/null
+++ b/apps/opencs/view/world/dialoguecreator.cpp
@@ -0,0 +1,35 @@
+
+#include "dialoguecreator.hpp"
+
+#include <components/esm/loaddial.hpp>
+
+#include "../../model/world/data.hpp"
+#include "../../model/world/commands.hpp"
+#include "../../model/world/columns.hpp"
+#include "../../model/world/idtable.hpp"
+
+void CSVWorld::DialogueCreator::configureCreateCommand (CSMWorld::CreateCommand& command) const
+{
+ int index =
+ dynamic_cast<CSMWorld::IdTable&> (*getData().getTableModel (getCollectionId())).
+ findColumnIndex (CSMWorld::Columns::ColumnId_DialogueType);
+
+ command.addValue (index, mType);
+}
+
+CSVWorld::DialogueCreator::DialogueCreator (CSMWorld::Data& data, QUndoStack& undoStack,
+ const CSMWorld::UniversalId& id, int type)
+: GenericCreator (data, undoStack, id), mType (type)
+{}
+
+CSVWorld::Creator *CSVWorld::TopicCreatorFactory::makeCreator (CSMWorld::Data& data,
+ QUndoStack& undoStack, const CSMWorld::UniversalId& id) const
+{
+ return new DialogueCreator (data, undoStack, id, ESM::Dialogue::Topic);
+}
+
+CSVWorld::Creator *CSVWorld::JournalCreatorFactory::makeCreator (CSMWorld::Data& data,
+ QUndoStack& undoStack, const CSMWorld::UniversalId& id) const
+{
+ return new DialogueCreator (data, undoStack, id, ESM::Dialogue::Journal);
+} \ No newline at end of file
diff --git a/apps/opencs/view/world/dialoguecreator.hpp b/apps/opencs/view/world/dialoguecreator.hpp
new file mode 100644
index 0000000000..26f866909a
--- /dev/null
+++ b/apps/opencs/view/world/dialoguecreator.hpp
@@ -0,0 +1,41 @@
+#ifndef CSV_WORLD_DIALOGUECREATOR_H
+#define CSV_WORLD_DIALOGUECREATOR_H
+
+#include "genericcreator.hpp"
+
+namespace CSVWorld
+{
+ class DialogueCreator : public GenericCreator
+ {
+ int mType;
+
+ protected:
+
+ virtual void configureCreateCommand (CSMWorld::CreateCommand& command) const;
+
+ public:
+
+ DialogueCreator (CSMWorld::Data& data, QUndoStack& undoStack,
+ const CSMWorld::UniversalId& id, int type);
+ };
+
+ class TopicCreatorFactory : public CreatorFactoryBase
+ {
+ public:
+
+ virtual Creator *makeCreator (CSMWorld::Data& data, QUndoStack& undoStack,
+ const CSMWorld::UniversalId& id) const;
+ ///< The ownership of the returned Creator is transferred to the caller.
+ };
+
+ class JournalCreatorFactory : public CreatorFactoryBase
+ {
+ public:
+
+ virtual Creator *makeCreator (CSMWorld::Data& data, QUndoStack& undoStack,
+ const CSMWorld::UniversalId& id) const;
+ ///< The ownership of the returned Creator is transferred to the caller.
+ };
+}
+
+#endif
diff --git a/apps/opencs/view/world/enumdelegate.cpp b/apps/opencs/view/world/enumdelegate.cpp
index dd194abe9a..fc9b7ee3b3 100644
--- a/apps/opencs/view/world/enumdelegate.cpp
+++ b/apps/opencs/view/world/enumdelegate.cpp
@@ -109,6 +109,18 @@ CSVWorld::EnumDelegateFactory::EnumDelegateFactory (const char **names, bool all
add (i, names[i]);
}
+CSVWorld::EnumDelegateFactory::EnumDelegateFactory (const std::vector<std::string>& names,
+ bool allowNone)
+{
+ if (allowNone)
+ add (-1, "");
+
+ int size = static_cast<int> (names.size());
+
+ for (int i=0; i<size; ++i)
+ add (i, names[i].c_str());
+}
+
CSVWorld::CommandDelegate *CSVWorld::EnumDelegateFactory::makeDelegate (QUndoStack& undoStack,
QObject *parent) const
{
diff --git a/apps/opencs/view/world/enumdelegate.hpp b/apps/opencs/view/world/enumdelegate.hpp
index b79516a09b..606f9278a1 100644
--- a/apps/opencs/view/world/enumdelegate.hpp
+++ b/apps/opencs/view/world/enumdelegate.hpp
@@ -54,6 +54,9 @@ namespace CSVWorld
///< \param names Array of char pointer with a 0-pointer as end mark
/// \param allowNone Use value of -1 for "none selected" (empty string)
+ EnumDelegateFactory (const std::vector<std::string>& names, bool allowNone = false);
+ /// \param allowNone Use value of -1 for "none selected" (empty string)
+
virtual CommandDelegate *makeDelegate (QUndoStack& undoStack, QObject *parent) const;
///< The ownership of the returned CommandDelegate is transferred to the caller.
diff --git a/apps/opencs/view/world/idtypedelegate.cpp b/apps/opencs/view/world/idtypedelegate.cpp
new file mode 100755
index 0000000000..ce4e8f0148
--- /dev/null
+++ b/apps/opencs/view/world/idtypedelegate.cpp
@@ -0,0 +1,46 @@
+#include "idtypedelegate.hpp"
+
+#include "../../model/world/universalid.hpp"
+
+CSVWorld::IdTypeDelegate::IdTypeDelegate
+ (const ValueList &values, const IconList &icons, QUndoStack& undoStack, QObject *parent)
+ : DataDisplayDelegate (values, icons, undoStack, parent)
+{}
+
+bool CSVWorld::IdTypeDelegate::updateEditorSetting (const QString &settingName, const QString &settingValue)
+{
+ /// \todo make the setting key a member variable, that is initialised from a constructor argument
+ if (settingName == "Referenceable ID Type Display")
+ {
+ if (settingValue == "Icon and Text")
+ mDisplayMode = Mode_IconAndText;
+
+ else if (settingValue == "Icon Only")
+ mDisplayMode = Mode_IconOnly;
+
+ else if (settingValue == "Text Only")
+ mDisplayMode = Mode_TextOnly;
+
+ return true;
+ }
+
+ return false;
+}
+
+
+CSVWorld::IdTypeDelegateFactory::IdTypeDelegateFactory()
+{
+ for (int i=0; i<CSMWorld::UniversalId::NumberOfTypes; ++i)
+ {
+ CSMWorld::UniversalId id (static_cast<CSMWorld::UniversalId::Type> (i));
+
+ DataDisplayDelegateFactory::add (id.getType(), QString::fromUtf8 (id.getTypeName().c_str()),
+ QString::fromUtf8 (id.getIcon().c_str()));
+ }
+}
+
+CSVWorld::CommandDelegate *CSVWorld::IdTypeDelegateFactory::makeDelegate (QUndoStack& undoStack,
+ QObject *parent) const
+{
+ return new IdTypeDelegate (mValues, mIcons, undoStack, parent);
+}
diff --git a/apps/opencs/view/world/refidtypedelegate.hpp b/apps/opencs/view/world/idtypedelegate.hpp
index 384aebb98d..ea80fd0d92 100755
--- a/apps/opencs/view/world/refidtypedelegate.hpp
+++ b/apps/opencs/view/world/idtypedelegate.hpp
@@ -1,5 +1,5 @@
-#ifndef REFIDTYPEDELEGATE_HPP
-#define REFIDTYPEDELEGATE_HPP
+#ifndef IDTYPEDELEGATE_HPP
+#define IDTYPEDELEGATE_HPP
#include "enumdelegate.hpp"
#include "util.hpp"
@@ -8,29 +8,23 @@
namespace CSVWorld
{
- class RefIdTypeDelegate : public DataDisplayDelegate
+ class IdTypeDelegate : public DataDisplayDelegate
{
public:
- RefIdTypeDelegate (const ValueList &mValues, const IconList &icons, QUndoStack& undoStack, QObject *parent);
+ IdTypeDelegate (const ValueList &mValues, const IconList &icons, QUndoStack& undoStack, QObject *parent);
virtual bool updateEditorSetting (const QString &settingName, const QString &settingValue);
};
- class RefIdTypeDelegateFactory : public DataDisplayDelegateFactory
+ class IdTypeDelegateFactory : public DataDisplayDelegateFactory
{
-
- typedef std::vector < std::pair <CSMWorld::UniversalId::Type, QString> > UidTypeList;
-
public:
- RefIdTypeDelegateFactory();
+
+ IdTypeDelegateFactory();
virtual CommandDelegate *makeDelegate (QUndoStack& undoStack, QObject *parent) const;
///< The ownership of the returned CommandDelegate is transferred to the caller.
-
- private:
- UidTypeList buildUidTypeList () const;
-
};
}
diff --git a/apps/opencs/view/world/recordstatusdelegate.cpp b/apps/opencs/view/world/recordstatusdelegate.cpp
index a0ffd3063d..8085ec7be4 100644
--- a/apps/opencs/view/world/recordstatusdelegate.cpp
+++ b/apps/opencs/view/world/recordstatusdelegate.cpp
@@ -1,8 +1,11 @@
#include "recordstatusdelegate.hpp"
+
#include <QPainter>
#include <QApplication>
#include <QUndoStack>
+
#include "../../model/settings/usersettings.hpp"
+#include "../../model/world/columns.hpp"
CSVWorld::RecordStatusDelegate::RecordStatusDelegate(const ValueList& values,
const IconList & icons,
@@ -37,9 +40,14 @@ bool CSVWorld::RecordStatusDelegate::updateEditorSetting (const QString &setting
CSVWorld::RecordStatusDelegateFactory::RecordStatusDelegateFactory()
{
- DataDisplayDelegateFactory::add ( CSMWorld::RecordBase::State_BaseOnly, "Base", ":./base.png");
- DataDisplayDelegateFactory::add ( CSMWorld::RecordBase::State_Deleted, "Deleted", ":./removed.png");
- DataDisplayDelegateFactory::add ( CSMWorld::RecordBase::State_Erased, "Deleted", ":./removed.png");
- DataDisplayDelegateFactory::add ( CSMWorld::RecordBase::State_Modified, "Modified", ":./modified.png");
- DataDisplayDelegateFactory::add ( CSMWorld::RecordBase::State_ModifiedOnly, "Added", ":./added.png");
+ std::vector<std::string> enums =
+ CSMWorld::Columns::getEnums (CSMWorld::Columns::ColumnId_Modification);
+
+ static const char *sIcons[] =
+ {
+ ":./base.png", ":./modified.png", ":./added.png", ":./removed.png", ":./removed.png", 0
+ };
+
+ for (int i=0; sIcons[i]; ++i)
+ add (i, enums.at (i).c_str(), sIcons[i]);
}
diff --git a/apps/opencs/view/world/refidtypedelegate.cpp b/apps/opencs/view/world/refidtypedelegate.cpp
deleted file mode 100755
index bf3acbb206..0000000000
--- a/apps/opencs/view/world/refidtypedelegate.cpp
+++ /dev/null
@@ -1,60 +0,0 @@
-#include "refidtypedelegate.hpp"
-#include "../../model/world/universalid.hpp"
-
-CSVWorld::RefIdTypeDelegate::RefIdTypeDelegate
- (const ValueList &values, const IconList &icons, QUndoStack& undoStack, QObject *parent)
- : DataDisplayDelegate (values, icons, undoStack, parent)
-{}
-
-CSVWorld::RefIdTypeDelegateFactory::RefIdTypeDelegateFactory()
-{
- UidTypeList uIdList = buildUidTypeList();
-
- for (UidTypeList::const_iterator it = uIdList.begin(); it != uIdList.end(); it++)
- {
- int i = it->first;
- DataDisplayDelegateFactory::add (i, QString::fromStdString(CSMWorld::UniversalId(it->first, "").getTypeName()), it->second);
- }
-}
-
-CSVWorld::CommandDelegate *CSVWorld::RefIdTypeDelegateFactory::makeDelegate (QUndoStack& undoStack,
- QObject *parent) const
-{
- return new RefIdTypeDelegate (mValues, mIcons, undoStack, parent);
-}
-
-CSVWorld::RefIdTypeDelegateFactory::UidTypeList CSVWorld::RefIdTypeDelegateFactory::buildUidTypeList() const
-{
- UidTypeList list;
-
- std::vector<CSMWorld::UniversalId::Type> types = CSMWorld::UniversalId::listReferenceableTypes();
-
- for (std::vector<CSMWorld::UniversalId::Type>::const_iterator iter (types.begin());
- iter!=types.end(); ++iter)
- {
- CSMWorld::UniversalId id (*iter, "");
-
- list.push_back (std::make_pair (id.getType(), id.getIcon().c_str()));
- }
-
- return list;
-}
-
-bool CSVWorld::RefIdTypeDelegate::updateEditorSetting (const QString &settingName, const QString &settingValue)
-{
- if (settingName == "Referenceable ID Type Display")
- {
- if (settingValue == "Icon and Text")
- mDisplayMode = Mode_IconAndText;
-
- else if (settingValue == "Icon Only")
- mDisplayMode = Mode_IconOnly;
-
- else if (settingValue == "Text Only")
- mDisplayMode = Mode_TextOnly;
-
- return true;
- }
-
- return false;
-}
diff --git a/apps/opencs/view/world/refrecordtypedelegate.cpp b/apps/opencs/view/world/refrecordtypedelegate.cpp
deleted file mode 100644
index 2bcb7ca50e..0000000000
--- a/apps/opencs/view/world/refrecordtypedelegate.cpp
+++ /dev/null
@@ -1,25 +0,0 @@
-#include "refrecordtypedelegate.hpp"
-#include "../../model/world/universalid.hpp"
-
-CSVWorld::RefRecordTypeDelegate::RefRecordTypeDelegate
- (const std::vector<std::pair<int, QString> > &values, QUndoStack& undoStack, QObject *parent)
- : EnumDelegate (values, undoStack, parent)
-{}
-
-CSVWorld::RefRecordTypeDelegateFactory::RefRecordTypeDelegateFactory()
-{
- unsigned int argSize = CSMWorld::UniversalId::getIdArgSize();
-
- for (unsigned int i = 0; i < argSize; i++)
- {
- std::pair<int, const char *> idPair = CSMWorld::UniversalId::getIdArgPair(i);
-
- mValues.push_back (std::pair<int, QString>(idPair.first, QString::fromUtf8(idPair.second)));
- }
-}
-
-CSVWorld::CommandDelegate *CSVWorld::RefRecordTypeDelegateFactory::makeDelegate (QUndoStack& undoStack,
- QObject *parent) const
-{
- return new RefRecordTypeDelegate (mValues, undoStack, parent);
-}
diff --git a/apps/opencs/view/world/refrecordtypedelegate.hpp b/apps/opencs/view/world/refrecordtypedelegate.hpp
deleted file mode 100644
index baec2cc2e9..0000000000
--- a/apps/opencs/view/world/refrecordtypedelegate.hpp
+++ /dev/null
@@ -1,58 +0,0 @@
-#ifndef REFRECORDTYPEDELEGATE_HPP
-#define REFRECORDTYPEDELEGATE_HPP
-
-#include "enumdelegate.hpp"
-#include "util.hpp"
-
-namespace CSVWorld
-{
- class RefRecordTypeDelegate : public EnumDelegate
- {
- public:
- RefRecordTypeDelegate (const std::vector<std::pair<int, QString> > &mValues, QUndoStack& undoStack, QObject *parent);
- };
-
- class RefRecordTypeDelegateFactory : public CommandDelegateFactory
- {
-
- std::vector<std::pair<int, QString> > mValues;
-
- public:
- RefRecordTypeDelegateFactory();
-
- virtual CommandDelegate *makeDelegate (QUndoStack& undoStack, QObject *parent) const;
- ///< The ownership of the returned CommandDelegate is transferred to the caller.
- };
-}
-/*
- class VarTypeDelegate : public EnumDelegate
- {
- private:
-
- virtual void addCommands (QAbstractItemModel *model,
- const QModelIndex& index, int type) const;
-
- public:
-
- VarTypeDelegate (const std::vector<std::pair<int, QString> >& values,
- QUndoStack& undoStack, QObject *parent);
- };
-
- class VarTypeDelegateFactory : public CommandDelegateFactory
- {
- std::vector<std::pair<int, QString> > mValues;
-
- public:
-
- VarTypeDelegateFactory (ESM::VarType type0 = ESM::VT_Unknown,
- ESM::VarType type1 = ESM::VT_Unknown, ESM::VarType type2 = ESM::VT_Unknown,
- ESM::VarType type3 = ESM::VT_Unknown);
-
- virtual CommandDelegate *makeDelegate (QUndoStack& undoStack, QObject *parent) const;
- ///< The ownership of the returned CommandDelegate is transferred to the caller.
-
- void add (ESM::VarType type);
- };
-*/
-
-#endif // REFRECORDTYPEDELEGATE_HPP
diff --git a/apps/opencs/view/world/scenesubview.cpp b/apps/opencs/view/world/scenesubview.cpp
new file mode 100644
index 0000000000..e3618c5493
--- /dev/null
+++ b/apps/opencs/view/world/scenesubview.cpp
@@ -0,0 +1,82 @@
+
+#include "scenesubview.hpp"
+
+#include <QVBoxLayout>
+#include <QHBoxLayout>
+#include <QLabel>
+
+#include "../../model/doc/document.hpp"
+
+#include "../filter/filterbox.hpp"
+
+#include "tablebottombox.hpp"
+#include "creator.hpp"
+#include "scenetoolbar.hpp"
+#include "scenetoolmode.hpp"
+
+CSVWorld::SceneSubView::SceneSubView (const CSMWorld::UniversalId& id, CSMDoc::Document& document)
+: SubView (id)
+{
+ QVBoxLayout *layout = new QVBoxLayout;
+
+ layout->setContentsMargins (QMargins (0, 0, 0, 0));
+
+ layout->addWidget (mBottom =
+ new TableBottomBox (NullCreatorFactory(), document.getData(), document.getUndoStack(), id,
+ this), 0);
+
+ QHBoxLayout *layout2 = new QHBoxLayout;
+
+ layout2->setContentsMargins (QMargins (0, 0, 0, 0));
+
+ SceneToolbar *toolbar = new SceneToolbar (48, this);
+// test
+SceneToolMode *tool = new SceneToolMode (toolbar);
+tool->addButton (":door.png", "a");
+tool->addButton (":GMST.png", "b");
+tool->addButton (":Info.png", "c");
+toolbar->addTool (tool);
+toolbar->addTool (new SceneToolMode (toolbar));
+toolbar->addTool (new SceneToolMode (toolbar));
+toolbar->addTool (new SceneToolMode (toolbar));
+ layout2->addWidget (toolbar, 0);
+
+ /// \todo replace with rendering widget
+ QPalette palette2 (palette());
+ palette2.setColor (QPalette::Background, Qt::white);
+ QLabel *placeholder = new QLabel ("Here goes the 3D scene", this);
+ placeholder->setAutoFillBackground (true);
+ placeholder->setPalette (palette2);
+ placeholder->setAlignment (Qt::AlignHCenter);
+
+ layout2->addWidget (placeholder, 1);
+
+ layout->insertLayout (0, layout2, 1);
+
+ CSVFilter::FilterBox *filterBox = new CSVFilter::FilterBox (document.getData(), this);
+
+ layout->insertWidget (0, filterBox);
+
+ QWidget *widget = new QWidget;
+
+ widget->setLayout (layout);
+
+ setWidget (widget);
+}
+
+void CSVWorld::SceneSubView::setEditLock (bool locked)
+{
+
+
+}
+
+void CSVWorld::SceneSubView::updateEditorSetting(const QString &settingName, const QString &settingValue)
+{
+
+
+}
+
+void CSVWorld::SceneSubView::setStatusBar (bool show)
+{
+ mBottom->setStatusBar (show);
+} \ No newline at end of file
diff --git a/apps/opencs/view/world/scenesubview.hpp b/apps/opencs/view/world/scenesubview.hpp
new file mode 100644
index 0000000000..a0fed908df
--- /dev/null
+++ b/apps/opencs/view/world/scenesubview.hpp
@@ -0,0 +1,37 @@
+#ifndef CSV_WORLD_SCENESUBVIEW_H
+#define CSV_WORLD_SCENESUBVIEW_H
+
+#include "../doc/subview.hpp"
+
+class QModelIndex;
+
+namespace CSMDoc
+{
+ class Document;
+}
+
+namespace CSVWorld
+{
+ class Table;
+ class TableBottomBox;
+ class CreatorFactoryBase;
+
+ class SceneSubView : public CSVDoc::SubView
+ {
+ Q_OBJECT
+
+ TableBottomBox *mBottom;
+
+ public:
+
+ SceneSubView (const CSMWorld::UniversalId& id, CSMDoc::Document& document);
+
+ virtual void setEditLock (bool locked);
+
+ virtual void updateEditorSetting (const QString& key, const QString& value);
+
+ virtual void setStatusBar (bool show);
+ };
+}
+
+#endif
diff --git a/apps/opencs/view/world/scenetool.cpp b/apps/opencs/view/world/scenetool.cpp
new file mode 100644
index 0000000000..320deb1ba9
--- /dev/null
+++ b/apps/opencs/view/world/scenetool.cpp
@@ -0,0 +1,17 @@
+
+#include "scenetool.hpp"
+
+#include "scenetoolbar.hpp"
+
+CSVWorld::SceneTool::SceneTool (SceneToolbar *parent) : QPushButton (parent)
+{
+ setSizePolicy (QSizePolicy (QSizePolicy::Fixed, QSizePolicy::Fixed));
+ setFixedSize (parent->getButtonSize(), parent->getButtonSize());
+
+ connect (this, SIGNAL (clicked()), this, SLOT (openRequest()));
+}
+
+void CSVWorld::SceneTool::openRequest()
+{
+ showPanel (parentWidget()->mapToGlobal (pos()));
+}
diff --git a/apps/opencs/view/world/scenetool.hpp b/apps/opencs/view/world/scenetool.hpp
new file mode 100644
index 0000000000..07e8b58d72
--- /dev/null
+++ b/apps/opencs/view/world/scenetool.hpp
@@ -0,0 +1,27 @@
+#ifndef CSV_WORLD_SCENETOOL_H
+#define CSV_WORLD_SCENETOOL_H
+
+#include <QPushButton>
+
+namespace CSVWorld
+{
+ class SceneToolbar;
+
+ ///< \brief Tool base class
+ class SceneTool : public QPushButton
+ {
+ Q_OBJECT
+
+ public:
+
+ SceneTool (SceneToolbar *parent);
+
+ virtual void showPanel (const QPoint& position) = 0;
+
+ private slots:
+
+ void openRequest();
+ };
+}
+
+#endif
diff --git a/apps/opencs/view/world/scenetoolbar.cpp b/apps/opencs/view/world/scenetoolbar.cpp
new file mode 100644
index 0000000000..2972c53913
--- /dev/null
+++ b/apps/opencs/view/world/scenetoolbar.cpp
@@ -0,0 +1,29 @@
+
+#include "scenetoolbar.hpp"
+
+#include <QVBoxLayout>
+
+#include "scenetool.hpp"
+
+CSVWorld::SceneToolbar::SceneToolbar (int buttonSize, QWidget *parent)
+: QWidget (parent), mButtonSize (buttonSize)
+{
+ setFixedWidth (mButtonSize);
+
+ mLayout = new QVBoxLayout (this);
+ mLayout->setAlignment (Qt::AlignTop);
+
+ mLayout->setContentsMargins (QMargins (0, 0, 0, 0));
+
+ setLayout (mLayout);
+}
+
+void CSVWorld::SceneToolbar::addTool (SceneTool *tool)
+{
+ mLayout->addWidget (tool, 0, Qt::AlignTop);
+}
+
+int CSVWorld::SceneToolbar::getButtonSize() const
+{
+ return mButtonSize;
+} \ No newline at end of file
diff --git a/apps/opencs/view/world/scenetoolbar.hpp b/apps/opencs/view/world/scenetoolbar.hpp
new file mode 100644
index 0000000000..f713ca3dff
--- /dev/null
+++ b/apps/opencs/view/world/scenetoolbar.hpp
@@ -0,0 +1,29 @@
+#ifndef CSV_WORLD_SCENETOOLBAR_H
+#define CSV_WORLD_SCENETOOLBAR_H
+
+#include <QWidget>
+
+class QVBoxLayout;
+
+namespace CSVWorld
+{
+ class SceneTool;
+
+ class SceneToolbar : public QWidget
+ {
+ Q_OBJECT
+
+ QVBoxLayout *mLayout;
+ int mButtonSize;
+
+ public:
+
+ SceneToolbar (int buttonSize, QWidget *parent = 0);
+
+ void addTool (SceneTool *tool);
+
+ int getButtonSize() const;
+ };
+}
+
+#endif
diff --git a/apps/opencs/view/world/scenetoolmode.cpp b/apps/opencs/view/world/scenetoolmode.cpp
new file mode 100644
index 0000000000..281d703b65
--- /dev/null
+++ b/apps/opencs/view/world/scenetoolmode.cpp
@@ -0,0 +1,56 @@
+
+#include "scenetoolmode.hpp"
+
+#include <QHBoxLayout>
+#include <QFrame>
+#include <QSignalMapper>
+
+#include "scenetoolbar.hpp"
+
+CSVWorld::SceneToolMode::SceneToolMode (SceneToolbar *parent)
+: SceneTool (parent), mButtonSize (parent->getButtonSize())
+{
+ mPanel = new QFrame (this, Qt::Popup);
+
+ mLayout = new QHBoxLayout (mPanel);
+
+ mLayout->setContentsMargins (QMargins (0, 0, 0, 0));
+
+ mPanel->setLayout (mLayout);
+}
+
+void CSVWorld::SceneToolMode::showPanel (const QPoint& position)
+{
+ mPanel->move (position);
+ mPanel->show();
+}
+
+void CSVWorld::SceneToolMode::addButton (const std::string& icon, const std::string& id)
+{
+ QPushButton *button = new QPushButton (QIcon (QPixmap (icon.c_str())), "", mPanel);
+ button->setSizePolicy (QSizePolicy (QSizePolicy::Fixed, QSizePolicy::Fixed));
+ button->setFixedSize (mButtonSize, mButtonSize);
+
+ mLayout->addWidget (button);
+
+ mButtons.insert (std::make_pair (button, id));
+
+ connect (button, SIGNAL (clicked()), this, SLOT (selected()));
+
+ if (mButtons.size()==1)
+ setIcon (button->icon());
+}
+
+void CSVWorld::SceneToolMode::selected()
+{
+ std::map<QPushButton *, std::string>::const_iterator iter =
+ mButtons.find (dynamic_cast<QPushButton *> (sender()));
+
+ if (iter!=mButtons.end())
+ {
+ mPanel->hide();
+
+ setIcon (iter->first->icon());
+ emit modeChanged (iter->second);
+ }
+} \ No newline at end of file
diff --git a/apps/opencs/view/world/scenetoolmode.hpp b/apps/opencs/view/world/scenetoolmode.hpp
new file mode 100644
index 0000000000..a8fe2b5a6c
--- /dev/null
+++ b/apps/opencs/view/world/scenetoolmode.hpp
@@ -0,0 +1,42 @@
+#ifndef CSV_WORLD_SCENETOOL_MODE_H
+#define CSV_WORLD_SCENETOOL_MODE_H
+
+#include "scenetool.hpp"
+
+#include <map>
+
+class QHBoxLayout;
+
+namespace CSVWorld
+{
+ class SceneToolbar;
+
+ ///< \brief Mode selector tool
+ class SceneToolMode : public SceneTool
+ {
+ Q_OBJECT
+
+ QWidget *mPanel;
+ QHBoxLayout *mLayout;
+ std::map<QPushButton *, std::string> mButtons; // widget, id
+ int mButtonSize;
+
+ public:
+
+ SceneToolMode (SceneToolbar *parent);
+
+ virtual void showPanel (const QPoint& position);
+
+ void addButton (const std::string& icon, const std::string& id);
+
+ signals:
+
+ void modeChanged (const std::string& id);
+
+ private slots:
+
+ void selected();
+ };
+}
+
+#endif
diff --git a/apps/opencs/view/world/scripthighlighter.cpp b/apps/opencs/view/world/scripthighlighter.cpp
index 288a3d12ac..e06dab3727 100644
--- a/apps/opencs/view/world/scripthighlighter.cpp
+++ b/apps/opencs/view/world/scripthighlighter.cpp
@@ -4,6 +4,7 @@
#include <sstream>
#include <components/compiler/scanner.hpp>
+#include <components/compiler/extensions0.hpp>
bool CSVWorld::ScriptHighlighter::parseInt (int value, const Compiler::TokenLoc& loc,
Compiler::Scanner& scanner)
@@ -22,7 +23,7 @@ bool CSVWorld::ScriptHighlighter::parseFloat (float value, const Compiler::Token
bool CSVWorld::ScriptHighlighter::parseName (const std::string& name, const Compiler::TokenLoc& loc,
Compiler::Scanner& scanner)
{
- highlight (loc, Type_Name);
+ highlight (loc, mContext.isId (name) ? Type_Id : Type_Name);
return true;
}
@@ -62,10 +63,10 @@ void CSVWorld::ScriptHighlighter::highlight (const Compiler::TokenLoc& loc, Type
setFormat (index, length, mScheme[type]);
}
-CSVWorld::ScriptHighlighter::ScriptHighlighter (QTextDocument *parent)
-: QSyntaxHighlighter (parent), Compiler::Parser (mErrorHandler, mContext)
+CSVWorld::ScriptHighlighter::ScriptHighlighter (const CSMWorld::Data& data, QTextDocument *parent)
+: QSyntaxHighlighter (parent), Compiler::Parser (mErrorHandler, mContext), mContext (data)
{
- /// \ŧodo replace this with user settings
+ /// \todo replace this with user settings
{
QTextCharFormat format;
format.setForeground (Qt::darkMagenta);
@@ -101,6 +102,16 @@ CSVWorld::ScriptHighlighter::ScriptHighlighter (QTextDocument *parent)
format.setForeground (Qt::green);
mScheme.insert (std::make_pair (Type_Comment, format));
}
+
+ {
+ QTextCharFormat format;
+ format.setForeground (Qt::blue);
+ mScheme.insert (std::make_pair (Type_Id, format));
+ }
+
+ // configure compiler
+ Compiler::registerExtensions (mExtensions);
+ mContext.setExtensions (&mExtensions);
}
void CSVWorld::ScriptHighlighter::highlightBlock (const QString& text)
@@ -114,5 +125,9 @@ void CSVWorld::ScriptHighlighter::highlightBlock (const QString& text)
scanner.scan (*this);
}
catch (...) {} // ignore syntax errors
+}
+void CSVWorld::ScriptHighlighter::invalidateIds()
+{
+ mContext.invalidateIds();
} \ No newline at end of file
diff --git a/apps/opencs/view/world/scripthighlighter.hpp b/apps/opencs/view/world/scripthighlighter.hpp
index 3ef6978097..495c2e6a3a 100644
--- a/apps/opencs/view/world/scripthighlighter.hpp
+++ b/apps/opencs/view/world/scripthighlighter.hpp
@@ -7,6 +7,7 @@
#include <components/compiler/nullerrorhandler.hpp>
#include <components/compiler/parser.hpp>
+#include <components/compiler/extensions.hpp>
#include "../../model/world/scriptcontext.hpp"
@@ -23,12 +24,14 @@ namespace CSVWorld
Type_Name,
Type_Keyword,
Type_Special,
- Type_Comment
+ Type_Comment,
+ Type_Id
};
private:
Compiler::NullErrorHandler mErrorHandler;
+ Compiler::Extensions mExtensions;
CSMWorld::ScriptContext mContext;
std::map<Type, QTextCharFormat> mScheme;
@@ -71,9 +74,11 @@ namespace CSVWorld
public:
- ScriptHighlighter (QTextDocument *parent);
+ ScriptHighlighter (const CSMWorld::Data& data, QTextDocument *parent);
virtual void highlightBlock (const QString& text);
+
+ void invalidateIds();
};
}
diff --git a/apps/opencs/view/world/scriptsubview.cpp b/apps/opencs/view/world/scriptsubview.cpp
index ab1c2d57c6..446c34e5f0 100644
--- a/apps/opencs/view/world/scriptsubview.cpp
+++ b/apps/opencs/view/world/scriptsubview.cpp
@@ -58,7 +58,13 @@ CSVWorld::ScriptSubView::ScriptSubView (const CSMWorld::UniversalId& id, CSMDoc:
connect (mModel, SIGNAL (rowsAboutToBeRemoved (const QModelIndex&, int, int)),
this, SLOT (rowsAboutToBeRemoved (const QModelIndex&, int, int)));
- new ScriptHighlighter (mEditor->document());
+ connect (&document.getData(), SIGNAL (idListChanged()), this, SLOT (idListChanged()));
+
+ mHighlighter = new ScriptHighlighter (document.getData(), mEditor->document());
+
+ connect (&mUpdateTimer, SIGNAL (timeout()), this, SLOT (updateHighlighting()));
+
+ mUpdateTimer.setSingleShot (true);
}
void CSVWorld::ScriptSubView::setEditLock (bool locked)
@@ -66,8 +72,19 @@ void CSVWorld::ScriptSubView::setEditLock (bool locked)
mEditor->setReadOnly (locked);
}
+void CSVWorld::ScriptSubView::idListChanged()
+{
+ mHighlighter->invalidateIds();
+
+ if (!mUpdateTimer.isActive())
+ mUpdateTimer.start (0);
+}
+
void CSVWorld::ScriptSubView::textChanged()
{
+ if (mChangeLocked)
+ return;
+
ChangeLock lock (*this);
mDocument.getUndoStack().push (new CSMWorld::ModifyCommand (*mModel,
@@ -79,6 +96,8 @@ void CSVWorld::ScriptSubView::dataChanged (const QModelIndex& topLeft, const QMo
if (mChangeLocked)
return;
+ ChangeLock lock (*this);
+
QModelIndex index = mModel->getModelIndex (getUniversalId().getId(), mColumn);
if (index.row()>=topLeft.row() && index.row()<=bottomRight.row() &&
@@ -96,4 +115,14 @@ void CSVWorld::ScriptSubView::rowsAboutToBeRemoved (const QModelIndex& parent, i
if (!parent.isValid() && index.row()>=start && index.row()<=end)
deleteLater();
+}
+
+void CSVWorld::ScriptSubView::updateHighlighting()
+{
+ if (mChangeLocked)
+ return;
+
+ ChangeLock lock (*this);
+
+ mHighlighter->rehighlight();
} \ No newline at end of file
diff --git a/apps/opencs/view/world/scriptsubview.hpp b/apps/opencs/view/world/scriptsubview.hpp
index 07d87d9476..7ceab70bae 100644
--- a/apps/opencs/view/world/scriptsubview.hpp
+++ b/apps/opencs/view/world/scriptsubview.hpp
@@ -3,6 +3,8 @@
#include "../doc/subview.hpp"
+#include <QTimer>
+
class QTextEdit;
class QModelIndex;
@@ -18,6 +20,8 @@ namespace CSMWorld
namespace CSVWorld
{
+ class ScriptHighlighter;
+
class ScriptSubView : public CSVDoc::SubView
{
Q_OBJECT
@@ -27,6 +31,8 @@ namespace CSVWorld
CSMWorld::IdTable *mModel;
int mColumn;
int mChangeLocked;
+ ScriptHighlighter *mHighlighter;
+ QTimer mUpdateTimer;
class ChangeLock
{
@@ -49,13 +55,19 @@ namespace CSVWorld
virtual void setEditLock (bool locked);
- private slots:
+ public slots:
+
+ void idListChanged();
void textChanged();
void dataChanged (const QModelIndex& topLeft, const QModelIndex& bottomRight);
void rowsAboutToBeRemoved (const QModelIndex& parent, int start, int end);
+
+ private slots:
+
+ void updateHighlighting();
};
}
diff --git a/apps/opencs/view/world/subviews.cpp b/apps/opencs/view/world/subviews.cpp
index d22e07d89c..3d98cf73ce 100644
--- a/apps/opencs/view/world/subviews.cpp
+++ b/apps/opencs/view/world/subviews.cpp
@@ -13,6 +13,8 @@
#include "cellcreator.hpp"
#include "referenceablecreator.hpp"
#include "referencecreator.hpp"
+#include "scenesubview.hpp"
+#include "dialoguecreator.hpp"
void CSVWorld::addSubViewFactories (CSVDoc::SubViewFactoryManager& manager)
{
@@ -52,6 +54,12 @@ void CSVWorld::addSubViewFactories (CSVDoc::SubViewFactoryManager& manager)
manager.add (CSMWorld::UniversalId::Type_References,
new CSVDoc::SubViewFactoryWithCreator<TableSubView, CreatorFactory<ReferenceCreator> >);
+ manager.add (CSMWorld::UniversalId::Type_Topics,
+ new CSVDoc::SubViewFactoryWithCreator<TableSubView, TopicCreatorFactory>);
+
+ manager.add (CSMWorld::UniversalId::Type_Journal,
+ new CSVDoc::SubViewFactoryWithCreator<TableSubView, JournalCreatorFactory>);
+
// Subviews for editing/viewing individual records
manager.add (CSMWorld::UniversalId::Type_Script, new CSVDoc::SubViewFactory<ScriptSubView>);
@@ -62,4 +70,5 @@ void CSVWorld::addSubViewFactories (CSVDoc::SubViewFactoryManager& manager)
new CSVDoc::SubViewFactoryWithCreator<TableSubView,
CreatorFactory<CSVFilter::FilterCreator> >);
+ manager.add (CSMWorld::UniversalId::Type_Scene, new CSVDoc::SubViewFactory<SceneSubView>);
} \ No newline at end of file
diff --git a/apps/opencs/view/world/table.cpp b/apps/opencs/view/world/table.cpp
index 72e78c738e..a58eb873f3 100644
--- a/apps/opencs/view/world/table.cpp
+++ b/apps/opencs/view/world/table.cpp
@@ -12,8 +12,8 @@
#include "../../model/world/idtableproxymodel.hpp"
#include "../../model/world/idtable.hpp"
#include "../../model/world/record.hpp"
+
#include "recordstatusdelegate.hpp"
-#include "refidtypedelegate.hpp"
#include "util.hpp"
void CSVWorld::Table::contextMenuEvent (QContextMenuEvent *event)
@@ -87,19 +87,33 @@ std::vector<std::string> CSVWorld::Table::listDeletableSelectedIds() const
{
QModelIndex index = mProxyModel->mapToSource (mProxyModel->index (iter->row(), 0));
+ // check record state
CSMWorld::RecordBase::State state =
static_cast<CSMWorld::RecordBase::State> (
mModel->data (mModel->index (index.row(), 1)).toInt());
- if (state!=CSMWorld::RecordBase::State_Deleted)
- {
- int columnIndex = mModel->findColumnIndex (CSMWorld::Columns::ColumnId_Id);
+ if (state==CSMWorld::RecordBase::State_Deleted)
+ continue;
- std::string id = mModel->data (mModel->index (index.row(), columnIndex)).
- toString().toUtf8().constData();
+ // check other columns (only relevant for a subset of the tables)
+ int dialogueTypeIndex =
+ mModel->searchColumnIndex (CSMWorld::Columns::ColumnId_DialogueType);
- deletableIds.push_back (id);
+ if (dialogueTypeIndex!=-1)
+ {
+ int type = mModel->data (mModel->index (index.row(), dialogueTypeIndex)).toInt();
+
+ if (type!=ESM::Dialogue::Topic && type!=ESM::Dialogue::Journal)
+ continue;
}
+
+ // add the id to the collection
+ int columnIndex = mModel->findColumnIndex (CSMWorld::Columns::ColumnId_Id);
+
+ std::string id = mModel->data (mModel->index (index.row(), columnIndex)).
+ toString().toUtf8().constData();
+
+ deletableIds.push_back (id);
}
}
diff --git a/apps/opencs/view/world/vartypedelegate.cpp b/apps/opencs/view/world/vartypedelegate.cpp
index 72cbaae428..15ce2dbaf2 100644
--- a/apps/opencs/view/world/vartypedelegate.cpp
+++ b/apps/opencs/view/world/vartypedelegate.cpp
@@ -4,6 +4,7 @@
#include <QUndoStack>
#include "../../model/world/commands.hpp"
+#include "../../model/world/columns.hpp"
void CSVWorld::VarTypeDelegate::addCommands (QAbstractItemModel *model, const QModelIndex& index, int type)
const
@@ -75,29 +76,11 @@ CSVWorld::CommandDelegate *CSVWorld::VarTypeDelegateFactory::makeDelegate (QUndo
void CSVWorld::VarTypeDelegateFactory::add (ESM::VarType type)
{
- struct Name
- {
- ESM::VarType mType;
- const char *mName;
- };
+ std::vector<std::string> enums =
+ CSMWorld::Columns::getEnums (CSMWorld::Columns::ColumnId_ValueType);
- static const Name sNames[] =
- {
- { ESM::VT_None, "empty" },
- { ESM::VT_Short, "short" },
- { ESM::VT_Int, "integer" },
- { ESM::VT_Long, "long" },
- { ESM::VT_Float, "float" },
- { ESM::VT_String, "string" },
- { ESM::VT_Unknown, 0 } // end marker
- };
-
- for (int i=0; sNames[i].mName; ++i)
- if (sNames[i].mType==type)
- {
- mValues.push_back (std::make_pair (type, sNames[i].mName));
- return;
- }
-
- throw std::logic_error ("Unsupported variable type");
+ if (type<0 && type>=enums.size())
+ throw std::logic_error ("Unsupported variable type");
+
+ mValues.push_back (std::make_pair (type, QString::fromUtf8 (enums[type].c_str())));
}
diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt
index a44fd4b343..807b1b5ff1 100644
--- a/apps/openmw/CMakeLists.txt
+++ b/apps/openmw/CMakeLists.txt
@@ -58,6 +58,7 @@ add_openmw_dir (mwworld
cells localscripts customdata weather inventorystore ptr actionopen actionread
actionequip timestamp actionalchemy cellstore actionapply actioneat
esmstore store recordcmp fallback actionrepair actionsoulgem livecellref actiondoor
+ contentloader esmloader omwloader
)
add_openmw_dir (mwclass
@@ -119,6 +120,10 @@ target_link_libraries(openmw
components
)
+if (USE_SYSTEM_TINYXML)
+ target_link_libraries(openmw ${TINYXML_LIBRARIES})
+endif()
+
if (NOT UNIX)
target_link_libraries(openmw ${SDL2MAIN_LIBRARY})
endif()
diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp
index a2eccbaf9a..e9c70e2aa1 100644
--- a/apps/openmw/engine.cpp
+++ b/apps/openmw/engine.cpp
@@ -261,34 +261,14 @@ void OMW::Engine::setCell (const std::string& cellName)
mCellName = cellName;
}
-// Set master file (esm)
-// - If the given name does not have an extension, ".esm" is added automatically
-
-void OMW::Engine::addMaster (const std::string& master)
+void OMW::Engine::addContentFile(const std::string& file)
{
- mMaster.push_back(master);
- std::string &str = mMaster.back();
+ if (file.find_last_of(".") == std::string::npos)
+ {
+ throw std::runtime_error("Missing extension in content file!");
+ }
- // Append .esm if not already there
- std::string::size_type sep = str.find_last_of (".");
- if (sep == std::string::npos)
- {
- str += ".esm";
- }
-}
-
-// Add plugin file (esp)
-void OMW::Engine::addPlugin (const std::string& plugin)
-{
- mPlugins.push_back(plugin);
- std::string &str = mPlugins.back();
-
- // Append .esp if not already there
- std::string::size_type sep = str.find_last_of (".");
- if (sep == std::string::npos)
- {
- str += ".esp";
- }
+ mContentFiles.push_back(file);
}
void OMW::Engine::setScriptsVerbosity(bool scriptsVerbosity)
@@ -370,7 +350,6 @@ void OMW::Engine::prepareEngine (Settings::Manager & settings)
addResourcesDirectory(mResDir / "mygui");
addResourcesDirectory(mResDir / "water");
addResourcesDirectory(mResDir / "shadows");
- addZipResource(mResDir / "mygui" / "Obliviontt.zip");
OEngine::Render::WindowSettings windowSettings;
windowSettings.fullscreen = settings.getBool("fullscreen", "Video");
@@ -399,23 +378,25 @@ void OMW::Engine::prepareEngine (Settings::Manager & settings)
mExtensions, mFpsLevel, mOgre, mCfgMgr.getLogPath().string() + std::string("/"),
mCfgMgr.getCachePath ().string(), mScriptConsoleMode, mTranslationDataStorage, mEncoding);
mEnvironment.setWindowManager (window);
- if (mNewGame)
- mEnvironment.getWindowManager()->setNewGame(true);
// Create the world
- mEnvironment.setWorld( new MWWorld::World (*mOgre, mFileCollections, mMaster, mPlugins,
+ mEnvironment.setWorld( new MWWorld::World (*mOgre, mFileCollections, mContentFiles,
mResDir, mCfgMgr.getCachePath(), mEncoder, mFallbackMap,
mActivationDistanceOverride));
MWBase::Environment::get().getWorld()->setupPlayer();
input->setPlayer(&mEnvironment.getWorld()->getPlayer());
window->initUI();
+ if (mNewGame)
+ // still redundant work here: recreate CharacterCreation(),
+ // double update visibility etc.
+ window->setNewGame(true);
window->renderWorldMap();
//Load translation data
mTranslationDataStorage.setEncoder(mEncoder);
- for (size_t i = 0; i < mMaster.size(); i++)
- mTranslationDataStorage.loadTranslationData(mFileCollections, mMaster[i]);
+ for (size_t i = 0; i < mContentFiles.size(); i++)
+ mTranslationDataStorage.loadTranslationData(mFileCollections, mContentFiles[i]);
Compiler::registerExtensions (mExtensions);
@@ -480,7 +461,7 @@ void OMW::Engine::prepareEngine (Settings::Manager & settings)
void OMW::Engine::go()
{
assert (!mCellName.empty());
- assert (!mMaster.empty());
+ assert (!mContentFiles.empty());
assert (!mOgre);
Settings::Manager settings;
diff --git a/apps/openmw/engine.hpp b/apps/openmw/engine.hpp
index 665b0094c1..553d290687 100644
--- a/apps/openmw/engine.hpp
+++ b/apps/openmw/engine.hpp
@@ -68,8 +68,7 @@ namespace OMW
boost::filesystem::path mResDir;
OEngine::Render::OgreRenderer *mOgre;
std::string mCellName;
- std::vector<std::string> mMaster;
- std::vector<std::string> mPlugins;
+ std::vector<std::string> mContentFiles;
int mFpsLevel;
bool mVerboseScripts;
bool mNewGame;
@@ -135,13 +134,11 @@ namespace OMW
/// Set start cell name (only interiors for now)
void setCell(const std::string& cellName);
- /// Set master file (esm)
- /// - If the given name does not have an extension, ".esm" is added automatically
- void addMaster(const std::string& master);
-
- /// Same as "addMaster", but for plugin files (esp)
- /// - If the given name does not have an extension, ".esp" is added automatically
- void addPlugin(const std::string& plugin);
+ /**
+ * @brief addContentFile - Adds content file (ie. esm/esp, or omwgame/omwaddon) to the content files container.
+ * @param file - filename (extension is required)
+ */
+ void addContentFile(const std::string& file);
/// Enable fps counter
void showFPS(int level);
diff --git a/apps/openmw/main.cpp b/apps/openmw/main.cpp
index 27afd734ae..33f740b311 100644
--- a/apps/openmw/main.cpp
+++ b/apps/openmw/main.cpp
@@ -110,11 +110,8 @@ bool parseOptions (int argc, char** argv, OMW::Engine& engine, Files::Configurat
("start", bpo::value<std::string>()->default_value("Beshara"),
"set initial cell")
- ("master", bpo::value<StringsVector>()->default_value(StringsVector(), "")
- ->multitoken(), "master file(s)")
-
- ("plugin", bpo::value<StringsVector>()->default_value(StringsVector(), "")
- ->multitoken(), "plugin file(s)")
+ ("content", bpo::value<StringsVector>()->default_value(StringsVector(), "")
+ ->multitoken(), "content file(s): esm/esp, or omwgame/omwaddon")
("anim-verbose", bpo::value<bool>()->implicit_value(true)
->default_value(false), "output animation indices files")
@@ -152,8 +149,6 @@ bool parseOptions (int argc, char** argv, OMW::Engine& engine, Files::Configurat
("activate-dist", bpo::value <int> ()->default_value (-1), "activation distance override");
- ;
-
bpo::parsed_options valid_opts = bpo::command_line_parser(argc, argv)
.options(desc).allow_unregistered().run();
@@ -211,29 +206,18 @@ bool parseOptions (int argc, char** argv, OMW::Engine& engine, Files::Configurat
engine.setResourceDir(variables["resources"].as<std::string>());
- // master and plugin
- StringsVector master = variables["master"].as<StringsVector>();
- if (master.empty())
+ StringsVector content = variables["content"].as<StringsVector>();
+ if (content.empty())
{
- std::cout << "No master file given. Aborting...\n";
- return false;
+ std::cout << "No content file given (esm/esp, nor omwgame/omwaddon). Aborting..." << std::endl;
+ return false;
}
- StringsVector plugin = variables["plugin"].as<StringsVector>();
- // Removed check for 255 files, which would be the hard-coded limit in Morrowind.
- // I'll keep the following variable in, maybe we can use it for something different.
- // Say, a feedback like "loading file x/cnt".
- // Commenting this out for now to silence compiler warning.
- //int cnt = master.size() + plugin.size();
-
- // Prepare loading master/plugin files (i.e. send filenames to engine)
- for (std::vector<std::string>::size_type i = 0; i < master.size(); i++)
- {
- engine.addMaster(master[i]);
- }
- for (std::vector<std::string>::size_type i = 0; i < plugin.size(); i++)
+ StringsVector::const_iterator it(content.begin());
+ StringsVector::const_iterator end(content.end());
+ for (; it != end; ++it)
{
- engine.addPlugin(plugin[i]);
+ engine.addContentFile(*it);
}
// startup-settings
diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp
index 6ca900a4d3..c39e878268 100644
--- a/apps/openmw/mwbase/world.hpp
+++ b/apps/openmw/mwbase/world.hpp
@@ -324,6 +324,7 @@ namespace MWBase
virtual void processChangedSettings (const Settings::CategorySettingVector& settings) = 0;
virtual bool isFlying(const MWWorld::Ptr &ptr) const = 0;
+ virtual bool isSlowFalling(const MWWorld::Ptr &ptr) const = 0;
virtual bool isSwimming(const MWWorld::Ptr &object) const = 0;
///Is the head of the creature underwater?
virtual bool isSubmerged(const MWWorld::Ptr &object) const = 0;
@@ -389,12 +390,22 @@ namespace MWBase
/// Returns true if teleport spell effects are allowed.
virtual bool isTeleportingEnabled() const = 0;
+ /// Enables or disables use of levitation spell effect.
+ virtual void enableLevitation(bool enable) = 0;
+
+ /// Returns true if levitation spell effect is allowed.
+ virtual bool isLevitationEnabled() const = 0;
+
/// Turn actor into werewolf or normal form.
virtual void setWerewolf(const MWWorld::Ptr& actor, bool werewolf) = 0;
/// Sets the NPC's Acrobatics skill to match the fWerewolfAcrobatics GMST.
/// It only applies to the current form the NPC is in.
virtual void applyWerewolfAcrobatics(const MWWorld::Ptr& actor) = 0;
+
+ virtual bool getGodModeState() = 0;
+
+ virtual bool toggleGodMode() = 0;
};
}
diff --git a/apps/openmw/mwclass/light.cpp b/apps/openmw/mwclass/light.cpp
index 7eefc6167c..a593eb295a 100644
--- a/apps/openmw/mwclass/light.cpp
+++ b/apps/openmw/mwclass/light.cpp
@@ -16,12 +16,34 @@
#include "../mwworld/inventorystore.hpp"
#include "../mwworld/cellstore.hpp"
#include "../mwworld/physicssystem.hpp"
+#include "../mwworld/customdata.hpp"
#include "../mwgui/tooltips.hpp"
#include "../mwrender/objects.hpp"
#include "../mwrender/renderinginterface.hpp"
+namespace
+{
+ struct CustomData : public MWWorld::CustomData
+ {
+ float mTime;
+ ///< Time remaining
+
+ CustomData(MWWorld::Ptr ptr)
+ {
+ MWWorld::LiveCellRef<ESM::Light> *ref = ptr.get<ESM::Light>();
+ mTime = ref->mBase->mData.mTime;
+ }
+ ///< Constructs this CustomData from the base values for Ptr.
+
+ virtual MWWorld::CustomData *clone() const
+ {
+ return new CustomData (*this);
+ }
+ };
+}
+
namespace MWClass
{
void Light::insertObjectRendering (const MWWorld::Ptr& ptr, MWRender::RenderingInterface& renderingInterface) const
@@ -182,6 +204,21 @@ namespace MWClass
return action;
}
+ void Light::setRemainingUsageTime (const MWWorld::Ptr& ptr, float duration) const
+ {
+ ensureCustomData(ptr);
+
+ float &timeRemaining = dynamic_cast<CustomData&> (*ptr.getRefData().getCustomData()).mTime;
+ timeRemaining = duration;
+ }
+
+ float Light::getRemainingUsageTime (const MWWorld::Ptr& ptr) const
+ {
+ ensureCustomData(ptr);
+
+ return dynamic_cast<CustomData&> (*ptr.getRefData().getCustomData()).mTime;
+ }
+
MWWorld::Ptr
Light::copyToCellImpl(const MWWorld::Ptr &ptr, MWWorld::CellStore &cell) const
{
@@ -191,6 +228,12 @@ namespace MWClass
return MWWorld::Ptr(&cell.mLights.insert(*ref), &cell);
}
+ void Light::ensureCustomData (const MWWorld::Ptr& ptr) const
+ {
+ if (!ptr.getRefData().getCustomData())
+ ptr.getRefData().setCustomData(new CustomData(ptr));
+ }
+
bool Light::canSell (const MWWorld::Ptr& item, int npcServices) const
{
return npcServices & ESM::NPC::Lights;
diff --git a/apps/openmw/mwclass/light.hpp b/apps/openmw/mwclass/light.hpp
index 79d662763b..c15228a6a0 100644
--- a/apps/openmw/mwclass/light.hpp
+++ b/apps/openmw/mwclass/light.hpp
@@ -10,6 +10,8 @@ namespace MWClass
virtual MWWorld::Ptr
copyToCellImpl(const MWWorld::Ptr &ptr, MWWorld::CellStore &cell) const;
+ void ensureCustomData (const MWWorld::Ptr& ptr) const;
+
public:
virtual void insertObjectRendering (const MWWorld::Ptr& ptr, MWRender::RenderingInterface& renderingInterface) const;
@@ -56,6 +58,12 @@ namespace MWClass
const;
///< Generate action for using via inventory menu
+ virtual void setRemainingUsageTime (const MWWorld::Ptr& ptr, float duration) const;
+ ///< Sets the remaining duration of the object.
+
+ virtual float getRemainingUsageTime (const MWWorld::Ptr& ptr) const;
+ ///< Returns the remaining duration of the object.
+
virtual std::string getModel(const MWWorld::Ptr &ptr) const;
virtual float getWeight (const MWWorld::Ptr& ptr) const;
diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp
index 073d1b1b92..01a0c0a6f9 100644
--- a/apps/openmw/mwclass/npc.cpp
+++ b/apps/openmw/mwclass/npc.cpp
@@ -7,6 +7,7 @@
#include <OgreSceneNode.h>
+#include <components/esm/loadmgef.hpp>
#include <components/esm/loadnpc.hpp>
#include "../mwbase/environment.hpp"
@@ -396,9 +397,10 @@ namespace MWClass
MWBase::Environment::get().getWindowManager()->messageBox("#{sTargetCriticalStrike}");
MWBase::Environment::get().getSoundManager()->playSound3D(victim, "critical damage", 1.0f, 1.0f);
}
- weapon.getCellRef().mCharge -= std::min(std::max(1,
- (int)(damage * gmst.find("fWeaponDamageMult")->getFloat())),
- weapon.getCellRef().mCharge);
+
+ if (!MWBase::Environment::get().getWorld()->getGodModeState())
+ weapon.getCellRef().mCharge -= std::min(std::max(1,
+ (int)(damage * gmst.find("fWeaponDamageMult")->getFloat())), weapon.getCellRef().mCharge);
}
healthdmg = true;
}
@@ -769,6 +771,37 @@ namespace MWClass
return x;
}
+ float Npc::getFallDamage(const MWWorld::Ptr &ptr, float fallHeight) const
+ {
+ MWBase::World *world = MWBase::Environment::get().getWorld();
+ const MWWorld::Store<ESM::GameSetting> &gmst = world->getStore().get<ESM::GameSetting>();
+
+ const float fallDistanceMin = gmst.find("fFallDamageDistanceMin")->getFloat();
+
+ if (fallHeight >= fallDistanceMin)
+ {
+ const float acrobaticsSkill = MWWorld::Class::get(ptr).getNpcStats (ptr).getSkill(ESM::Skill::Acrobatics).getModified();
+ const CustomData *npcdata = static_cast<const CustomData*>(ptr.getRefData().getCustomData());
+ const float jumpSpellBonus = npcdata->mNpcStats.getMagicEffects().get(MWMechanics::EffectKey(ESM::MagicEffect::Jump)).mMagnitude;
+ const float fallAcroBase = gmst.find("fFallAcroBase")->getFloat();
+ const float fallAcroMult = gmst.find("fFallAcroMult")->getFloat();
+ const float fallDistanceBase = gmst.find("fFallDistanceBase")->getFloat();
+ const float fallDistanceMult = gmst.find("fFallDistanceMult")->getFloat();
+
+ float x = fallHeight - fallDistanceMin;
+ x -= (1.5 * acrobaticsSkill) + jumpSpellBonus;
+ x = std::max(0.0f, x);
+
+ float a = fallAcroBase + fallAcroMult * (100 - acrobaticsSkill);
+ x = fallDistanceBase + fallDistanceMult * x;
+ x *= a;
+
+ return x;
+ }
+
+ return 0;
+ }
+
MWMechanics::Movement& Npc::getMovementSettings (const MWWorld::Ptr& ptr) const
{
ensureCustomData (ptr);
diff --git a/apps/openmw/mwclass/npc.hpp b/apps/openmw/mwclass/npc.hpp
index 3591d7c688..c39ca42ef4 100644
--- a/apps/openmw/mwclass/npc.hpp
+++ b/apps/openmw/mwclass/npc.hpp
@@ -97,6 +97,9 @@ namespace MWClass
virtual float getJump(const MWWorld::Ptr &ptr) const;
///< Return jump velocity (not accounting for movement)
+ virtual float getFallDamage(const MWWorld::Ptr &ptr, float fallHeight) const;
+ ///< Return amount of health points lost when falling
+
virtual MWMechanics::Movement& getMovementSettings (const MWWorld::Ptr& ptr) const;
///< Return desired movement.
diff --git a/apps/openmw/mwgui/fontloader.cpp b/apps/openmw/mwgui/fontloader.cpp
index ff160105a3..7a6317c163 100644
--- a/apps/openmw/mwgui/fontloader.cpp
+++ b/apps/openmw/mwgui/fontloader.cpp
@@ -9,6 +9,7 @@
#include <MyGUI_XmlDocument.h>
#include <MyGUI_FactoryManager.h>
+
#include <components/misc/stringops.hpp>
namespace
@@ -62,6 +63,58 @@ namespace
return unicode;
}
+
+ std::string getUtf8 (unsigned char c, ToUTF8::Utf8Encoder& encoder, ToUTF8::FromType encoding)
+ {
+ if (encoding == ToUTF8::WINDOWS_1250)
+ {
+ unsigned char win1250;
+ std::map<unsigned char, unsigned char> conv;
+ conv[0x80] = 0xc6;
+ conv[0x81] = 0x9c;
+ conv[0x82] = 0xe6;
+ conv[0x83] = 0xb3;
+ conv[0x84] = 0xf1;
+ conv[0x85] = 0xb9;
+ conv[0x86] = 0xbf;
+ conv[0x87] = 0x9f;
+ conv[0x88] = 0xea;
+ conv[0x89] = 0xea;
+ conv[0x8a] = 0x0; // not contained in win1250
+ conv[0x8b] = 0x0; // not contained in win1250
+ conv[0x8c] = 0x8f;
+ conv[0x8d] = 0xaf;
+ conv[0x8e] = 0xa5;
+ conv[0x8f] = 0x8c;
+ conv[0x90] = 0xca;
+ conv[0x93] = 0xa3;
+ conv[0x94] = 0xf6;
+ conv[0x95] = 0xf3;
+ conv[0x96] = 0xaf;
+ conv[0x97] = 0x8f;
+ conv[0x99] = 0xd3;
+ conv[0x9a] = 0xd1;
+ conv[0x9c] = 0x0; // not contained in win1250
+ conv[0xa0] = 0xb9;
+ conv[0xa1] = 0xaf;
+ conv[0xa2] = 0xf3;
+ conv[0xa3] = 0xbf;
+ conv[0xa4] = 0x0; // not contained in win1250
+ conv[0xe1] = 0x8c;
+ conv[0xe1] = 0x8c;
+ conv[0xe3] = 0x0; // not contained in win1250
+ conv[0xf5] = 0x0; // not contained in win1250
+
+ if (conv.find(c) != conv.end())
+ win1250 = conv[c];
+ else
+ win1250 = c;
+ return encoder.getUtf8(std::string(1, win1250));
+ }
+ else
+ return encoder.getUtf8(std::string(1, c));
+ }
+
}
namespace MWGui
@@ -184,7 +237,7 @@ namespace MWGui
int h = data[i].bottom_left.y*height - y1;
ToUTF8::Utf8Encoder encoder(mEncoding);
- unsigned long unicodeVal = utf8ToUnicode(encoder.getUtf8(std::string(1, (unsigned char)(i))));
+ unsigned long unicodeVal = utf8ToUnicode(getUtf8(i, encoder, mEncoding));
MyGUI::xml::ElementPtr code = codes->createChild("Code");
code->addAttribute("index", unicodeVal);
diff --git a/apps/openmw/mwgui/hud.cpp b/apps/openmw/mwgui/hud.cpp
index f9d31bdcd6..e7b9f9c015 100644
--- a/apps/openmw/mwgui/hud.cpp
+++ b/apps/openmw/mwgui/hud.cpp
@@ -28,6 +28,7 @@ namespace MWGui
, mStamina(NULL)
, mDrowning(NULL)
, mDrowningFrame(NULL)
+ , mDrowningFlash(NULL)
, mWeapImage(NULL)
, mSpellImage(NULL)
, mWeapStatus(NULL)
@@ -53,6 +54,7 @@ namespace MWGui
, mSpellVisible(true)
, mWorldMouseOver(false)
, mEnemyHealthTimer(0)
+ , mIsDrowning(false)
{
setCoord(0,0, width, height);
@@ -75,6 +77,7 @@ namespace MWGui
//Drowning bar
getWidget(mDrowningFrame, "DrowningFrame");
getWidget(mDrowning, "Drowning");
+ getWidget(mDrowningFlash, "Flash");
mDrowning->setProgressRange(200);
const MyGUI::IntSize& viewSize = MyGUI::RenderManager::getInstance().getViewSize();
@@ -207,7 +210,15 @@ namespace MWGui
void HUD::setDrowningTimeLeft(float time)
{
- mDrowning->setProgressPosition(time/20.0*200.0);
+ size_t progress = time/20.0*200.0;
+ mDrowning->setProgressPosition(progress);
+
+ bool isDrowning = (progress == 0);
+ if (isDrowning && !mIsDrowning) // Just started drowning
+ mDrowningFlashTheta = 0.0f; // Start out on bright red every time.
+
+ mDrowningFlash->setVisible(isDrowning);
+ mIsDrowning = isDrowning;
}
void HUD::setDrowningBarVisible(bool visible)
@@ -250,6 +261,7 @@ namespace MWGui
// remove object from the container it was coming from
mDragAndDrop->mSourceModel->removeItem(mDragAndDrop->mItem, mDragAndDrop->mDraggedCount);
mDragAndDrop->finish();
+ mDragAndDrop->mSourceModel->update();
}
else
{
@@ -366,6 +378,9 @@ namespace MWGui
mEnemyHealth->setVisible(false);
mWeaponSpellBox->setPosition(mWeaponSpellBox->getPosition() + MyGUI::IntPoint(0,20));
}
+
+ if (mIsDrowning)
+ mDrowningFlashTheta += dt * Ogre::Math::TWO_PI;
}
void HUD::onResChange(int width, int height)
@@ -608,6 +623,12 @@ namespace MWGui
mEnemyHealth->setProgressRange(100);
mEnemyHealth->setProgressPosition(stats.getHealth().getCurrent() / stats.getHealth().getModified() * 100);
}
+
+ if (mIsDrowning)
+ {
+ float intensity = (cos(mDrowningFlashTheta) + 1.0f) / 2.0f;
+ mDrowningFlash->setColour(MyGUI::Colour(intensity, intensity, intensity));
+ }
}
void HUD::setEnemy(const MWWorld::Ptr &enemy)
diff --git a/apps/openmw/mwgui/hud.hpp b/apps/openmw/mwgui/hud.hpp
index c40742a603..04206fbc88 100644
--- a/apps/openmw/mwgui/hud.hpp
+++ b/apps/openmw/mwgui/hud.hpp
@@ -67,7 +67,7 @@ namespace MWGui
MyGUI::ImageBox* mCrosshair;
MyGUI::TextBox* mCellNameBox;
MyGUI::TextBox* mWeaponSpellBox;
- MyGUI::Widget* mDrowningFrame;
+ MyGUI::Widget *mDrowningFrame, *mDrowningFlash;
MyGUI::Widget* mDummy;
@@ -101,6 +101,9 @@ namespace MWGui
MWWorld::Ptr mEnemy;
float mEnemyHealthTimer;
+ bool mIsDrowning;
+ float mDrowningFlashTheta;
+
void onWorldClicked(MyGUI::Widget* _sender);
void onWorldMouseOver(MyGUI::Widget* _sender, int x, int y);
void onWorldMouseLostFocus(MyGUI::Widget* _sender, MyGUI::Widget* _new);
diff --git a/apps/openmw/mwgui/loadingscreen.cpp b/apps/openmw/mwgui/loadingscreen.cpp
index 9b63dfa76d..4bd383c2f3 100644
--- a/apps/openmw/mwgui/loadingscreen.cpp
+++ b/apps/openmw/mwgui/loadingscreen.cpp
@@ -23,6 +23,7 @@ namespace MWGui
, mLastWallpaperChangeTime(0.f)
, mFirstLoad(true)
, mProgress(0)
+ , mVSyncWasEnabled(false)
{
getWidget(mLoadingText, "LoadingText");
getWidget(mProgressBar, "ProgressBar");
@@ -67,6 +68,14 @@ namespace MWGui
void LoadingScreen::loadingOn()
{
+ // Temporarily turn off VSync, we want to do actual loading rather than waiting for the screen to sync.
+ // Threaded loading would be even better, of course - especially because some drivers force VSync to on and we can't change it.
+ // In Ogre 1.8, the swapBuffers argument is useless and setVSyncEnabled is bugged with GLX, nothing we can do :/
+ mVSyncWasEnabled = mWindow->isVSyncEnabled();
+ #if OGRE_VERSION >= (1 << 16 | 9 << 8 | 0)
+ mWindow->setVSyncEnabled(false);
+ #endif
+
setVisible(true);
if (mFirstLoad)
@@ -83,6 +92,12 @@ namespace MWGui
void LoadingScreen::loadingOff()
{
+ // Re-enable vsync now.
+ // In Ogre 1.8, the swapBuffers argument is useless and setVSyncEnabled is bugged with GLX, nothing we can do :/
+ #if OGRE_VERSION >= (1 << 16 | 9 << 8 | 0)
+ mWindow->setVSyncEnabled(mVSyncWasEnabled);
+ #endif
+
setVisible(false);
MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Loading);
@@ -212,7 +227,8 @@ namespace MWGui
// caused a sync / flush and would be expensive).
// We're doing this so we can do some actual loading while the GPU is busy with the render.
// This means the render is lagging a frame behind, but this is hardly noticable.
- mWindow->swapBuffers(false); // never Vsync, makes no sense here
+ mWindow->swapBuffers();
+
mWindow->update(false);
if (!hasCompositor)
diff --git a/apps/openmw/mwgui/loadingscreen.hpp b/apps/openmw/mwgui/loadingscreen.hpp
index dde8ff63aa..2d1d7431f8 100644
--- a/apps/openmw/mwgui/loadingscreen.hpp
+++ b/apps/openmw/mwgui/loadingscreen.hpp
@@ -57,6 +57,8 @@ namespace MWGui
Ogre::StringVector mResources;
+ bool mVSyncWasEnabled;
+
void changeWallpaper();
void draw();
diff --git a/apps/openmw/mwgui/mainmenu.cpp b/apps/openmw/mwgui/mainmenu.cpp
index 88227c7512..1db6e9ecd2 100644
--- a/apps/openmw/mwgui/mainmenu.cpp
+++ b/apps/openmw/mwgui/mainmenu.cpp
@@ -70,7 +70,10 @@ namespace MWGui
{
MWBase::Environment::get().getSoundManager()->playSound("Menu Click", 1.f, 1.f);
if (sender == mButtons["return"])
+ {
+ MWBase::Environment::get().getSoundManager ()->resumeSounds (MWBase::SoundManager::Play_TypeSfx);
MWBase::Environment::get().getWindowManager ()->removeGuiMode (GM_MainMenu);
+ }
else if (sender == mButtons["options"])
MWBase::Environment::get().getWindowManager ()->pushGuiMode (GM_Settings);
else if (sender == mButtons["exitgame"])
diff --git a/apps/openmw/mwgui/messagebox.cpp b/apps/openmw/mwgui/messagebox.cpp
index 45da1bf17e..48d7ec1717 100644
--- a/apps/openmw/mwgui/messagebox.cpp
+++ b/apps/openmw/mwgui/messagebox.cpp
@@ -14,6 +14,7 @@ namespace MWGui
mMessageBoxSpeed = 0.1;
mInterMessageBoxe = NULL;
mStaticMessageBox = NULL;
+ mLastButtonPressed = -1;
}
void MessageBoxManager::onFrame (float frameDuration)
@@ -62,6 +63,7 @@ namespace MWGui
}
if(mInterMessageBoxe != NULL && mInterMessageBoxe->mMarkedToDelete) {
+ mLastButtonPressed = mInterMessageBoxe->readPressedButton();
delete mInterMessageBoxe;
mInterMessageBoxe = NULL;
MWBase::Environment::get().getInputManager()->changeInputMode(
@@ -107,6 +109,7 @@ namespace MWGui
}
mInterMessageBoxe = new InteractiveMessageBox(*this, message, buttons);
+ mLastButtonPressed = -1;
return true;
}
@@ -154,11 +157,9 @@ namespace MWGui
int MessageBoxManager::readPressedButton ()
{
- if(mInterMessageBoxe != NULL)
- {
- return mInterMessageBoxe->readPressedButton();
- }
- return -1;
+ int pressed = mLastButtonPressed;
+ mLastButtonPressed = -1;
+ return pressed;
}
@@ -421,9 +422,7 @@ namespace MWGui
int InteractiveMessageBox::readPressedButton ()
{
- int pressed = mButtonPressed;
- mButtonPressed = -1;
- return pressed;
+ return mButtonPressed;
}
}
diff --git a/apps/openmw/mwgui/messagebox.hpp b/apps/openmw/mwgui/messagebox.hpp
index 4ef645f5e6..63840cfe2c 100644
--- a/apps/openmw/mwgui/messagebox.hpp
+++ b/apps/openmw/mwgui/messagebox.hpp
@@ -56,6 +56,7 @@ namespace MWGui
MessageBox* mStaticMessageBox;
std::vector<MessageBoxManagerTimer> mTimers;
float mMessageBoxSpeed;
+ int mLastButtonPressed;
};
class MessageBox : public OEngine::GUI::Layout
diff --git a/apps/openmw/mwgui/settingswindow.cpp b/apps/openmw/mwgui/settingswindow.cpp
index 3dfa17badc..923b9d01d6 100644
--- a/apps/openmw/mwgui/settingswindow.cpp
+++ b/apps/openmw/mwgui/settingswindow.cpp
@@ -363,8 +363,12 @@ namespace MWGui
else if (_sender == mVSyncButton)
{
Settings::Manager::setBool("vsync", "Video", newState);
+ // Ogre::Window::setVSyncEnabled is bugged in 1.8
+#if OGRE_VERSION < (1 << 16 | 9 << 8 | 0)
MWBase::Environment::get().getWindowManager()->
messageBox("VSync will be applied after a restart", std::vector<std::string>());
+#endif
+ apply();
}
else
{
diff --git a/apps/openmw/mwgui/spellicons.cpp b/apps/openmw/mwgui/spellicons.cpp
index 9812c0f8a9..0c303485af 100644
--- a/apps/openmw/mwgui/spellicons.cpp
+++ b/apps/openmw/mwgui/spellicons.cpp
@@ -2,6 +2,9 @@
#include <boost/lexical_cast.hpp>
+#include <sstream>
+#include <iomanip>
+
#include "../mwbase/world.hpp"
#include "../mwbase/environment.hpp"
#include "../mwbase/windowmanager.hpp"
@@ -169,13 +172,34 @@ namespace MWGui
MWBase::Environment::get().getWindowManager()->getGameSettingString(
ESM::Attribute::sGmstAttributeIds[effectIt->mKey.mArg], "") + ")";
- if (!(effect->mData.mFlags & ESM::MagicEffect::NoMagnitude))
+ ESM::MagicEffect::MagnitudeDisplayType displayType = effect->getMagnitudeDisplayType();
+ if (displayType == ESM::MagicEffect::MDT_TimesInt)
+ {
+ std::string timesInt = MWBase::Environment::get().getWindowManager()->getGameSettingString("sXTimesINT", "");
+ std::stringstream formatter;
+ formatter << std::fixed << std::setprecision(1) << " " << (effectIt->mMagnitude / 10.0f) << timesInt;
+ sourcesDescription += formatter.str();
+ }
+ else if ( displayType != ESM::MagicEffect::MDT_None )
{
- std::string pt = MWBase::Environment::get().getWindowManager()->getGameSettingString("spoint", "");
- std::string pts = MWBase::Environment::get().getWindowManager()->getGameSettingString("spoints", "");
-
sourcesDescription += ": " + boost::lexical_cast<std::string>(effectIt->mMagnitude);
- sourcesDescription += " " + ((effectIt->mMagnitude > 1) ? pts : pt);
+
+ if ( displayType == ESM::MagicEffect::MDT_Percentage )
+ sourcesDescription += MWBase::Environment::get().getWindowManager()->getGameSettingString("spercent", "");
+ else if ( displayType == ESM::MagicEffect::MDT_Feet )
+ sourcesDescription += " " + MWBase::Environment::get().getWindowManager()->getGameSettingString("sfeet", "");
+ else if ( displayType == ESM::MagicEffect::MDT_Level )
+ {
+ sourcesDescription += " " + ((effectIt->mMagnitude > 1) ?
+ MWBase::Environment::get().getWindowManager()->getGameSettingString("sLevels", "") :
+ MWBase::Environment::get().getWindowManager()->getGameSettingString("sLevel", "") );
+ }
+ else // ESM::MagicEffect::MDT_Points
+ {
+ sourcesDescription += " " + ((effectIt->mMagnitude > 1) ?
+ MWBase::Environment::get().getWindowManager()->getGameSettingString("spoints", "") :
+ MWBase::Environment::get().getWindowManager()->getGameSettingString("spoint", "") );
+ }
}
}
diff --git a/apps/openmw/mwgui/widgets.cpp b/apps/openmw/mwgui/widgets.cpp
index dea64ae8cf..3fc3187e80 100644
--- a/apps/openmw/mwgui/widgets.cpp
+++ b/apps/openmw/mwgui/widgets.cpp
@@ -2,6 +2,9 @@
#include <boost/lexical_cast.hpp>
+#include <sstream>
+#include <iomanip>
+
#include <MyGUI_ProgressBar.h>
#include <MyGUI_ImageBox.h>
#include <MyGUI_ControllerManager.h>
@@ -405,6 +408,10 @@ namespace MWGui
std::string pt = MWBase::Environment::get().getWindowManager()->getGameSettingString("spoint", "");
std::string pts = MWBase::Environment::get().getWindowManager()->getGameSettingString("spoints", "");
+ std::string pct = MWBase::Environment::get().getWindowManager()->getGameSettingString("spercent", "");
+ std::string ft = MWBase::Environment::get().getWindowManager()->getGameSettingString("sfeet", "");
+ std::string lvl = MWBase::Environment::get().getWindowManager()->getGameSettingString("sLevel", "");
+ std::string lvls = MWBase::Environment::get().getWindowManager()->getGameSettingString("sLevels", "");
std::string to = " " + MWBase::Environment::get().getWindowManager()->getGameSettingString("sTo", "") + " ";
std::string sec = " " + MWBase::Environment::get().getWindowManager()->getGameSettingString("ssecond", "");
std::string secs = " " + MWBase::Environment::get().getWindowManager()->getGameSettingString("sseconds", "");
@@ -421,13 +428,32 @@ namespace MWGui
spellLine += " " + MWBase::Environment::get().getWindowManager()->getGameSettingString(ESM::Attribute::sGmstAttributeIds[mEffectParams.mAttribute], "");
}
- if ((mEffectParams.mMagnMin >= 0 || mEffectParams.mMagnMax >= 0) && !(magicEffect->mData.mFlags & ESM::MagicEffect::NoMagnitude))
- {
- if (mEffectParams.mMagnMin == mEffectParams.mMagnMax)
- spellLine += " " + boost::lexical_cast<std::string>(mEffectParams.mMagnMin) + " " + ((mEffectParams.mMagnMin == 1) ? pt : pts);
- else
- {
- spellLine += " " + boost::lexical_cast<std::string>(mEffectParams.mMagnMin) + to + boost::lexical_cast<std::string>(mEffectParams.mMagnMax) + " " + pts;
+ if (mEffectParams.mMagnMin >= 0 || mEffectParams.mMagnMax >= 0) {
+ ESM::MagicEffect::MagnitudeDisplayType displayType = magicEffect->getMagnitudeDisplayType();
+ if ( displayType == ESM::MagicEffect::MDT_TimesInt ) {
+ std::string timesInt = MWBase::Environment::get().getWindowManager()->getGameSettingString("sXTimesINT", "");
+ std::stringstream formatter;
+
+ formatter << std::fixed << std::setprecision(1) << " " << (mEffectParams.mMagnMin / 10.0f);
+ if (mEffectParams.mMagnMin != mEffectParams.mMagnMax)
+ formatter << to << (mEffectParams.mMagnMax / 10.0f);
+ formatter << timesInt;
+
+ spellLine += formatter.str();
+ }
+ else if ( displayType != ESM::MagicEffect::MDT_None ) {
+ spellLine += " " + boost::lexical_cast<std::string>(mEffectParams.mMagnMin);
+ if (mEffectParams.mMagnMin != mEffectParams.mMagnMax)
+ spellLine += to + boost::lexical_cast<std::string>(mEffectParams.mMagnMax);
+
+ if ( displayType == ESM::MagicEffect::MDT_Percentage )
+ spellLine += pct;
+ else if ( displayType == ESM::MagicEffect::MDT_Feet )
+ spellLine += " " + ft;
+ else if ( displayType == ESM::MagicEffect::MDT_Level )
+ spellLine += " " + ((mEffectParams.mMagnMin == 1 && mEffectParams.mMagnMax == 1) ? lvl : lvls );
+ else // ESM::MagicEffect::MDT_Points
+ spellLine += " " + ((mEffectParams.mMagnMin == 1 && mEffectParams.mMagnMax == 1) ? pt : pts );
}
}
diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp
index bf8b664daa..4b4d2dfd19 100644
--- a/apps/openmw/mwgui/windowmanagerimp.cpp
+++ b/apps/openmw/mwgui/windowmanagerimp.cpp
@@ -61,20 +61,23 @@ namespace MWGui
const Compiler::Extensions& extensions, int fpsLevel, OEngine::Render::OgreRenderer *ogre,
const std::string& logpath, const std::string& cacheDir, bool consoleOnlyScripts,
Translation::Storage& translationDataStorage, ToUTF8::FromType encoding)
- : mGuiManager(NULL)
- , mConsoleOnlyScripts(consoleOnlyScripts)
+ : mConsoleOnlyScripts(consoleOnlyScripts)
+ , mGuiManager(NULL)
, mRendering(ogre)
, mHud(NULL)
, mMap(NULL)
, mMenu(NULL)
- , mStatsWindow(NULL)
, mToolTips(NULL)
+ , mStatsWindow(NULL)
, mMessageBoxManager(NULL)
, mConsole(NULL)
, mJournal(NULL)
, mDialogueWindow(NULL)
- , mBookWindow(NULL)
+ , mContainerWindow(NULL)
+ , mDragAndDrop(NULL)
+ , mInventoryWindow(NULL)
, mScrollWindow(NULL)
+ , mBookWindow(NULL)
, mCountDialog(NULL)
, mTradeWindow(NULL)
, mSpellBuyingWindow(NULL)
@@ -83,27 +86,37 @@ namespace MWGui
, mConfirmationDialog(NULL)
, mAlchemyWindow(NULL)
, mSpellWindow(NULL)
+ , mQuickKeysMenu(NULL)
, mLoadingScreen(NULL)
- , mCharGen(NULL)
, mLevelupDialog(NULL)
, mWaitDialog(NULL)
, mSpellCreationDialog(NULL)
, mEnchantingDialog(NULL)
, mTrainingWindow(NULL)
, mMerchantRepair(NULL)
- , mRepair(NULL)
, mSoulgemDialog(NULL)
+ , mRepair(NULL)
, mCompanionWindow(NULL)
+ , mTranslationDataStorage (translationDataStorage)
+ , mSoftwareCursor(NULL)
+ , mCharGen(NULL)
+ , mInputBlocker(NULL)
+ , mCrosshairEnabled(Settings::Manager::getBool ("crosshair", "HUD"))
+ , mSubtitlesEnabled(Settings::Manager::getBool ("subtitles", "GUI"))
+ , mHudEnabled(true)
+ , mCursorVisible(true)
, mPlayerName()
, mPlayerRaceId()
, mPlayerAttributes()
- , mPlayerMajorSkills()
, mPlayerMinorSkills()
+ , mPlayerMajorSkills()
, mPlayerSkillValues()
, mPlayerHealth()
, mPlayerMagicka()
, mPlayerFatigue()
, mGui(NULL)
+ , mGuiModes()
+ , mCursorManager(NULL)
, mGarbageDialogs()
, mShown(GW_ALL)
, mForceHidden(GW_None)
@@ -113,13 +126,7 @@ namespace MWGui
, mFPS(0.0f)
, mTriangleCount(0)
, mBatchCount(0)
- , mCrosshairEnabled(Settings::Manager::getBool ("crosshair", "HUD"))
- , mSubtitlesEnabled(Settings::Manager::getBool ("subtitles", "GUI"))
- , mHudEnabled(true)
- , mTranslationDataStorage (translationDataStorage)
- , mCursorManager(NULL)
, mUseHardwareCursors(Settings::Manager::getBool("hardware cursors", "GUI"))
- , mCursorVisible(true)
{
// Set up the GUI system
mGuiManager = new OEngine::GUI::MyGUIManager(mRendering->getWindow(), mRendering->getScene(), false, logpath);
diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp
index 1039a0dced..4746260edf 100644
--- a/apps/openmw/mwinput/inputmanagerimp.cpp
+++ b/apps/openmw/mwinput/inputmanagerimp.cpp
@@ -468,6 +468,41 @@ namespace MWInput
bool InputManager::keyPressed( const SDL_KeyboardEvent &arg )
{
+ // Cut, copy & paste
+ MyGUI::Widget* focus = MyGUI::InputManager::getInstance().getKeyFocusWidget();
+ if (focus)
+ {
+ MyGUI::EditBox* edit = focus->castType<MyGUI::EditBox>(false);
+ if (edit && !edit->getEditReadOnly())
+ {
+ if (arg.keysym.sym == SDLK_v && (arg.keysym.mod & SDL_Keymod(KMOD_CTRL)))
+ {
+ char* text = SDL_GetClipboardText();
+
+ if (text)
+ {
+ edit->addText(MyGUI::UString(text));
+ SDL_free(text);
+ }
+ }
+ if (arg.keysym.sym == SDLK_x && (arg.keysym.mod & SDL_Keymod(KMOD_CTRL)))
+ {
+ std::string text = edit->getTextSelection();
+ if (text.length())
+ {
+ SDL_SetClipboardText(text.c_str());
+ edit->deleteTextSelection();
+ }
+ }
+ if (arg.keysym.sym == SDLK_c && (arg.keysym.mod & SDL_Keymod(KMOD_CTRL)))
+ {
+ std::string text = edit->getTextSelection();
+ if (text.length())
+ SDL_SetClipboardText(text.c_str());
+ }
+ }
+ }
+
mInputBinder->keyPressed (arg);
if(arg.keysym.sym == SDLK_RETURN
@@ -577,15 +612,15 @@ namespace MWInput
rot[0] = -y;
rot[1] = 0.0f;
rot[2] = x;
-
- // Only actually turn player when we're not in vanity mode
+
+ // Only actually turn player when we're not in vanity mode
if(!MWBase::Environment::get().getWorld()->vanityRotateCamera(rot))
{
mPlayer->yaw(x/scale);
mPlayer->pitch(-y/scale);
}
- if (arg.zrel)
+ if (arg.zrel && mControlSwitch["playerviewswitch"]) //Check to make sure you are allowed to zoomout and there is a change
{
MWBase::Environment::get().getWorld()->changeVanityModeScale(arg.zrel);
MWBase::Environment::get().getWorld()->setCameraDistance(arg.zrel, true, true);
@@ -617,9 +652,15 @@ namespace MWInput
if (MWBase::Environment::get().getWindowManager()->isGuiMode () && MWBase::Environment::get().getWindowManager()->getMode () == MWGui::GM_Video)
MWBase::Environment::get().getWorld ()->stopVideo ();
else if (MWBase::Environment::get().getWindowManager()->containsMode(MWGui::GM_MainMenu))
+ {
MWBase::Environment::get().getWindowManager()->popGuiMode();
+ MWBase::Environment::get().getSoundManager()->resumeSounds (MWBase::SoundManager::Play_TypeSfx);
+ }
else
+ {
MWBase::Environment::get().getWindowManager()->pushGuiMode (MWGui::GM_MainMenu);
+ MWBase::Environment::get().getSoundManager()->pauseSounds (MWBase::SoundManager::Play_TypeSfx);
+ }
}
void InputManager::toggleSpell()
diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp
index 566d4bc505..42851dea39 100644
--- a/apps/openmw/mwmechanics/actors.cpp
+++ b/apps/openmw/mwmechanics/actors.cpp
@@ -31,18 +31,24 @@ namespace MWMechanics
calculateDynamicStats (ptr);
calculateCreatureStatModifiers (ptr);
- // AI
if(!MWBase::Environment::get().getWindowManager()->isGuiMode())
{
+ // AI
CreatureStats& creatureStats = MWWorld::Class::get (ptr).getCreatureStats (ptr);
creatureStats.getAiSequence().execute (ptr);
+
+ // fatigue restoration
+ calculateRestoration(ptr, duration);
}
}
void Actors::updateNpc (const MWWorld::Ptr& ptr, float duration, bool paused)
{
if(!paused)
+ {
updateDrowning(ptr, duration);
+ updateEquippedLight(ptr, duration);
+ }
}
void Actors::adjustMagicEffects (const MWWorld::Ptr& creature)
@@ -93,39 +99,29 @@ namespace MWMechanics
void Actors::calculateRestoration (const MWWorld::Ptr& ptr, float duration)
{
CreatureStats& stats = MWWorld::Class::get (ptr).getCreatureStats (ptr);
+ const MWWorld::Store<ESM::GameSetting>& settings = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>();
+
+ int endurance = stats.getAttribute (ESM::Attribute::Endurance).getModified ();
+
+ float capacity = MWWorld::Class::get(ptr).getCapacity(ptr);
+ float encumbrance = MWWorld::Class::get(ptr).getEncumbrance(ptr);
+ float normalizedEncumbrance = (capacity == 0 ? 1 : encumbrance/capacity);
+ if (normalizedEncumbrance > 1)
+ normalizedEncumbrance = 1;
if (duration == 3600)
{
- bool stunted = stats.getMagicEffects ().get(MWMechanics::EffectKey(ESM::MagicEffect::StuntedMagicka)).mMagnitude > 0;
+ // the actor is sleeping, restore health and magicka
- int endurance = stats.getAttribute (ESM::Attribute::Endurance).getModified ();
+ bool stunted = stats.getMagicEffects ().get(MWMechanics::EffectKey(ESM::MagicEffect::StuntedMagicka)).mMagnitude > 0;
DynamicStat<float> health = stats.getHealth();
health.setCurrent (health.getCurrent() + 0.1 * endurance);
stats.setHealth (health);
- const MWWorld::ESMStore& store = MWBase::Environment::get().getWorld()->getStore();
-
- float fFatigueReturnBase = store.get<ESM::GameSetting>().find("fFatigueReturnBase")->getFloat ();
- float fFatigueReturnMult = store.get<ESM::GameSetting>().find("fFatigueReturnMult")->getFloat ();
- float fEndFatigueMult = store.get<ESM::GameSetting>().find("fEndFatigueMult")->getFloat ();
-
- float capacity = MWWorld::Class::get(ptr).getCapacity(ptr);
- float encumbrance = MWWorld::Class::get(ptr).getEncumbrance(ptr);
- float normalizedEncumbrance = (capacity == 0 ? 1 : encumbrance/capacity);
- if (normalizedEncumbrance > 1)
- normalizedEncumbrance = 1;
-
- float x = fFatigueReturnBase + fFatigueReturnMult * (1 - normalizedEncumbrance);
- x *= fEndFatigueMult * endurance;
-
- DynamicStat<float> fatigue = stats.getFatigue();
- fatigue.setCurrent (fatigue.getCurrent() + 3600 * x);
- stats.setFatigue (fatigue);
-
if (!stunted)
{
- float fRestMagicMult = store.get<ESM::GameSetting>().find("fRestMagicMult")->getFloat ();
+ float fRestMagicMult = settings.find("fRestMagicMult")->getFloat ();
DynamicStat<float> magicka = stats.getMagicka();
magicka.setCurrent (magicka.getCurrent()
@@ -133,6 +129,19 @@ namespace MWMechanics
stats.setMagicka (magicka);
}
}
+
+ // restore fatigue
+
+ float fFatigueReturnBase = settings.find("fFatigueReturnBase")->getFloat ();
+ float fFatigueReturnMult = settings.find("fFatigueReturnMult")->getFloat ();
+ float fEndFatigueMult = settings.find("fEndFatigueMult")->getFloat ();
+
+ float x = fFatigueReturnBase + fFatigueReturnMult * (1 - normalizedEncumbrance);
+ x *= fEndFatigueMult * endurance;
+
+ DynamicStat<float> fatigue = stats.getFatigue();
+ fatigue.setCurrent (fatigue.getCurrent() + duration * x);
+ stats.setFatigue (fatigue);
}
void Actors::calculateCreatureStatModifiers (const MWWorld::Ptr& ptr)
@@ -196,6 +205,49 @@ namespace MWMechanics
stats.setTimeToStartDrowning(20);
}
+ void Actors::updateEquippedLight (const MWWorld::Ptr& ptr, float duration)
+ {
+ //If holding a light...
+ MWWorld::InventoryStore &inventoryStore = MWWorld::Class::get(ptr).getInventoryStore(ptr);
+ MWWorld::ContainerStoreIterator heldIter =
+ inventoryStore.getSlot(MWWorld::InventoryStore::Slot_CarriedLeft);
+
+ if(heldIter.getType() == MWWorld::ContainerStore::Type_Light)
+ {
+ // Use time from the player's light
+ bool isPlayer = ptr.getRefData().getHandle()=="player";
+ if(isPlayer)
+ {
+ float timeRemaining = heldIter->getClass().getRemainingUsageTime(*heldIter);
+
+ // -1 is infinite light source. Other negative values are treated as 0.
+ if(timeRemaining != -1.0f)
+ {
+ timeRemaining -= duration;
+
+ if(timeRemaining > 0.0f)
+ heldIter->getClass().setRemainingUsageTime(*heldIter, timeRemaining);
+ else
+ {
+ heldIter->getRefData().setCount(0); // remove it
+ return;
+ }
+ }
+ }
+
+ // Both NPC and player lights extinguish in water.
+ if(MWBase::Environment::get().getWorld()->isSwimming(ptr))
+ {
+ heldIter->getRefData().setCount(0); // remove it
+
+ // ...But, only the player makes a sound.
+ if(isPlayer)
+ MWBase::Environment::get().getSoundManager()->playSound("torch out",
+ 1.0, 1.0, MWBase::SoundManager::Play_TypeSfx, MWBase::SoundManager::Play_NoEnv);
+ }
+ }
+ }
+
Actors::Actors() : mDuration (0) {}
void Actors::addActor (const MWWorld::Ptr& ptr)
@@ -275,9 +327,9 @@ namespace MWMechanics
continue;
}
- // workaround: always keep player alive for now
- // \todo remove workaround, once player death can be handled
- if(iter->first.getRefData().getHandle()=="player")
+ // If it's the player and God Mode is turned on, keep it alive
+ if(iter->first.getRefData().getHandle()=="player" &&
+ MWBase::Environment::get().getWorld()->getGodModeState())
{
MWMechanics::DynamicStat<float> stat(stats.getHealth());
diff --git a/apps/openmw/mwmechanics/actors.hpp b/apps/openmw/mwmechanics/actors.hpp
index 69878a000e..a77e52ba30 100644
--- a/apps/openmw/mwmechanics/actors.hpp
+++ b/apps/openmw/mwmechanics/actors.hpp
@@ -44,6 +44,8 @@ namespace MWMechanics
void updateDrowning (const MWWorld::Ptr& ptr, float duration);
+ void updateEquippedLight (const MWWorld::Ptr& ptr, float duration);
+
public:
Actors();
diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp
index ec2bb1b59e..c4260d907d 100644
--- a/apps/openmw/mwmechanics/character.cpp
+++ b/apps/openmw/mwmechanics/character.cpp
@@ -767,10 +767,25 @@ void CharacterController::update(float duration)
}
if(sneak || inwater || flying)
+ {
vec.z = 0.0f;
+ mFallHeight = mPtr.getRefData().getPosition().pos[2];
+ }
if(!onground && !flying && !inwater)
{
+ // The player is in the air (either getting up —ascending part of jump— or falling).
+
+ if (world->isSlowFalling(mPtr))
+ {
+ // SlowFalling spell effect is active, do not keep previous fall height
+ mFallHeight = mPtr.getRefData().getPosition().pos[2];
+ }
+ else
+ {
+ mFallHeight = std::max(mFallHeight, mPtr.getRefData().getPosition().pos[2]);
+ }
+
const MWWorld::Store<ESM::GameSetting> &gmst = world->getStore().get<ESM::GameSetting>();
forcestateupdate = (mJumpState != JumpState_Falling);
@@ -794,6 +809,8 @@ void CharacterController::update(float duration)
}
else if(vec.z > 0.0f && mJumpState == JumpState_None)
{
+ // The player has started a jump.
+
float z = cls.getJump(mPtr);
if(vec.x == 0 && vec.y == 0)
vec = Ogre::Vector3(0.0f, 0.0f, z);
@@ -803,13 +820,49 @@ void CharacterController::update(float duration)
vec = Ogre::Vector3(lat.x, lat.y, 1.0f) * z * 0.707f;
}
- //decrease fatigue by fFatigueJumpBase + (1 - normalizedEncumbrance) * fFatigueJumpMult;
+ // advance acrobatics
+ cls.skillUsageSucceeded(mPtr, ESM::Skill::Acrobatics, 0);
+
+ // decrease fatigue
+ const MWWorld::Store<ESM::GameSetting> &gmst = world->getStore().get<ESM::GameSetting>();
+ const float fatigueJumpBase = gmst.find("fFatigueJumpBase")->getFloat();
+ const float fatigueJumpMult = gmst.find("fFatigueJumpMult")->getFloat();
+ const float normalizedEncumbrance = cls.getEncumbrance(mPtr) / cls.getCapacity(mPtr);
+ const int fatigueDecrease = fatigueJumpBase + (1 - normalizedEncumbrance) * fatigueJumpMult;
+ DynamicStat<float> fatigue = cls.getCreatureStats(mPtr).getFatigue();
+ fatigue.setCurrent(fatigue.getCurrent() - fatigueDecrease);
+ cls.getCreatureStats(mPtr).setFatigue(fatigue);
}
else if(mJumpState == JumpState_Falling)
{
+ // The player is landing.
+
forcestateupdate = true;
mJumpState = JumpState_Landing;
vec.z = 0.0f;
+
+ float healthLost = cls.getFallDamage(mPtr, mFallHeight - mPtr.getRefData().getPosition().pos[2]);
+ if (healthLost > 0.0f)
+ {
+ const float fatigueTerm = cls.getCreatureStats(mPtr).getFatigueTerm();
+
+ // inflict fall damages
+ DynamicStat<float> health = cls.getCreatureStats(mPtr).getHealth();
+ int realHealthLost = healthLost * (1.0f - 0.25 * fatigueTerm);
+ health.setCurrent(health.getCurrent() - realHealthLost);
+ cls.getCreatureStats(mPtr).setHealth(health);
+
+ // report acrobatics progression
+ cls.skillUsageSucceeded(mPtr, ESM::Skill::Acrobatics, 1);
+
+ const float acrobaticsSkill = cls.getNpcStats(mPtr).getSkill(ESM::Skill::Acrobatics).getModified();
+ if (healthLost > (acrobaticsSkill * fatigueTerm))
+ {
+ //TODO: actor falls over
+ }
+ }
+
+ mFallHeight = mPtr.getRefData().getPosition().pos[2];
}
else
{
diff --git a/apps/openmw/mwmechanics/character.hpp b/apps/openmw/mwmechanics/character.hpp
index c943b95977..8670b385e3 100644
--- a/apps/openmw/mwmechanics/character.hpp
+++ b/apps/openmw/mwmechanics/character.hpp
@@ -3,6 +3,8 @@
#include <OgreVector3.h>
+#include <components/esm/loadmgef.hpp>
+
#include "../mwworld/ptr.hpp"
namespace MWWorld
@@ -154,6 +156,9 @@ class CharacterController
float mSecondsOfSwimming;
float mSecondsOfRunning;
+ // used for acrobatics progress and fall damages
+ float mFallHeight;
+
std::string mAttackType; // slash, chop or thrust
void refreshCurrentAnims(CharacterState idle, CharacterState movement, bool force=false);
diff --git a/apps/openmw/mwmechanics/magiceffects.cpp b/apps/openmw/mwmechanics/magiceffects.cpp
index 1a7b348170..3ed458c3fa 100644
--- a/apps/openmw/mwmechanics/magiceffects.cpp
+++ b/apps/openmw/mwmechanics/magiceffects.cpp
@@ -151,8 +151,7 @@ namespace MWMechanics
for (Collection::const_iterator iter (prev.begin()); iter!=prev.end(); ++iter)
{
Collection::const_iterator other = now.mCollection.find (iter->first);
-
- if (other==prev.end())
+ if (other==now.end())
{
result.add (iter->first, EffectParam() - iter->second);
}
diff --git a/apps/openmw/mwrender/.gitignore b/apps/openmw/mwrender/.gitignore
new file mode 100644
index 0000000000..3367afdbbf
--- /dev/null
+++ b/apps/openmw/mwrender/.gitignore
@@ -0,0 +1 @@
+old
diff --git a/apps/openmw/mwrender/camera.cpp b/apps/openmw/mwrender/camera.cpp
index 36f53c0fea..9af3987a8e 100644
--- a/apps/openmw/mwrender/camera.cpp
+++ b/apps/openmw/mwrender/camera.cpp
@@ -187,6 +187,12 @@ namespace MWRender
rotateCamera(Ogre::Vector3(getPitch(), 0.f, getYaw()), false);
}
+ void Camera::setSneakOffset()
+ {
+ if(mAnimation)
+ mAnimation->addFirstPersonOffset(Ogre::Vector3(0.f, 0.f, -9.8f));
+ }
+
float Camera::getYaw()
{
if(mVanity.enabled || mPreviewMode)
diff --git a/apps/openmw/mwrender/camera.hpp b/apps/openmw/mwrender/camera.hpp
index dc552371e6..baf2f3685a 100644
--- a/apps/openmw/mwrender/camera.hpp
+++ b/apps/openmw/mwrender/camera.hpp
@@ -79,6 +79,12 @@ namespace MWRender
void togglePreviewMode(bool enable);
+ /// \brief Lowers the camera for sneak.
+ /// As animation is tied to the camera, this needs
+ /// to be set each frame after the animation is
+ /// applied.
+ void setSneakOffset();
+
bool isFirstPerson() const
{ return !(mVanity.enabled || mPreviewMode || !mFirstPersonView); }
diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp
index 13b5971e2a..9ffe53eabb 100644
--- a/apps/openmw/mwrender/npcanimation.cpp
+++ b/apps/openmw/mwrender/npcanimation.cpp
@@ -84,7 +84,8 @@ NpcAnimation::NpcAnimation(const MWWorld::Ptr& ptr, Ogre::SceneNode* node, MWWor
mWeapon(inv.end()),
mShield(inv.end()),
mViewMode(viewMode),
- mShowWeapons(false)
+ mShowWeapons(false),
+ mFirstPersonOffset(0.f, 0.f, 0.f)
{
mNpc = mPtr.get<ESM::NPC>()->mBase;
@@ -392,6 +393,11 @@ void NpcAnimation::updateParts(bool forceupdate)
}
}
+void NpcAnimation::addFirstPersonOffset(const Ogre::Vector3 &offset)
+{
+ mFirstPersonOffset += offset;
+}
+
class SetObjectGroup {
int mGroup;
@@ -448,7 +454,12 @@ Ogre::Vector3 NpcAnimation::runAnimation(float timepassed)
float pitch = mCamera->getPitch();
Ogre::Node *node = baseinst->getBone("Bip01 Neck");
node->pitch(Ogre::Radian(pitch*0.75f), Ogre::Node::TS_WORLD);
+
+ // This has to be done before this function ends;
+ // updateSkeletonInstance, below, touches the hands.
+ node->translate(mFirstPersonOffset, Ogre::Node::TS_WORLD);
}
+ mFirstPersonOffset = 0.f; // reset the X, Y, Z offset for the next frame.
for(size_t i = 0;i < ESM::PRT_Count;i++)
{
diff --git a/apps/openmw/mwrender/npcanimation.hpp b/apps/openmw/mwrender/npcanimation.hpp
index 24205acafd..b1abf97af0 100644
--- a/apps/openmw/mwrender/npcanimation.hpp
+++ b/apps/openmw/mwrender/npcanimation.hpp
@@ -64,6 +64,8 @@ private:
int mPartslots[ESM::PRT_Count]; //Each part slot is taken by clothing, armor, or is empty
int mPartPriorities[ESM::PRT_Count];
+ Ogre::Vector3 mFirstPersonOffset;
+
void updateNpcBase();
NifOgre::ObjectList insertBoundedPart(const std::string &model, int group, const std::string &bonename);
@@ -89,6 +91,11 @@ public:
void updateParts(bool forceupdate = false);
+ /// \brief Applies a translation to the arms and hands.
+ /// This may be called multiple times before the animation
+ /// is updated to add additional offsets.
+ void addFirstPersonOffset(const Ogre::Vector3 &offset);
+
/// Rebuilds the NPC, updating their root model, animation sources, and equipment.
void rebuild();
};
diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp
index e03b2ccfcf..93425191dd 100644
--- a/apps/openmw/mwrender/renderingmanager.cpp
+++ b/apps/openmw/mwrender/renderingmanager.cpp
@@ -354,6 +354,15 @@ void RenderingManager::update (float duration, bool paused)
mCamera->setCameraDistance(test.second * orig.distance(dest), false, false);
}
+ // Sink the camera while sneaking
+ bool isSneaking = MWWorld::Class::get(player).getStance(player, MWWorld::Class::Sneak);
+ bool isInAir = !world->isOnGround(player);
+ bool isSwimming = world->isSwimming(player);
+
+ if(isSneaking && !(isSwimming || isInAir))
+ mCamera->setSneakOffset();
+
+
mOcclusionQuery->update(duration);
mVideoPlayer->update ();
@@ -760,6 +769,13 @@ void RenderingManager::processChangedSettings(const Settings::CategorySettingVec
|| it->second == "resolution y"
|| it->second == "fullscreen"))
changeRes = true;
+ else if (it->first == "Video" && it->second == "vsync")
+ {
+ // setVSyncEnabled is bugged in 1.8
+#if OGRE_VERSION >= (1 << 16 | 9 << 8 | 0)
+ mRendering.getWindow()->setVSyncEnabled(Settings::Manager::getBool("vsync", "Video"));
+#endif
+ }
else if (it->second == "field of view" && it->first == "General")
mRendering.setFov(Settings::Manager::getFloat("field of view", "General"));
else if ((it->second == "texture filtering" && it->first == "General")
diff --git a/apps/openmw/mwscript/docs/vmformat.txt b/apps/openmw/mwscript/docs/vmformat.txt
index 08b4991753..7bbb336999 100644
--- a/apps/openmw/mwscript/docs/vmformat.txt
+++ b/apps/openmw/mwscript/docs/vmformat.txt
@@ -351,5 +351,8 @@ op 0x200021b: SetWerewolfAcrobatics
op 0x200021c: SetWerewolfAcrobaticsExplicit
op 0x200021d: ShowVars
op 0x200021e: ShowVarsExplicit
+op 0x200021f: ToggleGodMode
+op 0x2000220: DisableLevitation
+op 0x2000221: EnableLevitation
-opcodes 0x200021f-0x3ffffff unused
+opcodes 0x2000222-0x3ffffff unused
diff --git a/apps/openmw/mwscript/miscextensions.cpp b/apps/openmw/mwscript/miscextensions.cpp
index 3141f13a25..4ae1136e22 100644
--- a/apps/openmw/mwscript/miscextensions.cpp
+++ b/apps/openmw/mwscript/miscextensions.cpp
@@ -635,7 +635,18 @@ namespace MWScript
world->enableTeleporting(Enable);
}
};
-
+
+ template <bool Enable>
+ class OpEnableLevitation : public Interpreter::Opcode0
+ {
+ public:
+
+ virtual void execute (Interpreter::Runtime& runtime)
+ {
+ MWBase::World *world = MWBase::Environment::get().getWorld();
+ world->enableLevitation(Enable);
+ }
+ };
template <class R>
class OpShowVars : public Interpreter::Opcode0
@@ -717,6 +728,19 @@ namespace MWScript
}
};
+ class OpToggleGodMode : public Interpreter::Opcode0
+ {
+ public:
+ virtual void execute (Interpreter::Runtime& runtime)
+ {
+ InterpreterContext& context = static_cast<InterpreterContext&> (runtime.getContext());
+
+ bool enabled = MWBase::Environment::get().getWorld()->toggleGodMode();
+
+ context.report (enabled ? "God Mode -> On" : "God Mode -> Off");
+ }
+ };
+
void installOpcodes (Interpreter::Interpreter& interpreter)
{
@@ -775,6 +799,9 @@ namespace MWScript
interpreter.installSegment5 (Compiler::Misc::opcodeEnableTeleporting, new OpEnableTeleporting<true>);
interpreter.installSegment5 (Compiler::Misc::opcodeShowVars, new OpShowVars<ImplicitRef>);
interpreter.installSegment5 (Compiler::Misc::opcodeShowVarsExplicit, new OpShowVars<ExplicitRef>);
+ interpreter.installSegment5 (Compiler::Misc::opcodeToggleGodMode, new OpToggleGodMode);
+ interpreter.installSegment5 (Compiler::Misc::opcodeDisableLevitation, new OpEnableLevitation<false>);
+ interpreter.installSegment5 (Compiler::Misc::opcodeEnableLevitation, new OpEnableLevitation<true>);
}
}
}
diff --git a/apps/openmw/mwscript/statsextensions.cpp b/apps/openmw/mwscript/statsextensions.cpp
index eca9d279b2..603515ff4a 100644
--- a/apps/openmw/mwscript/statsextensions.cpp
+++ b/apps/openmw/mwscript/statsextensions.cpp
@@ -1081,7 +1081,6 @@ namespace MWScript
}
};
-
void installOpcodes (Interpreter::Interpreter& interpreter)
{
for (int i=0; i<Compiler::Stats::numberOfAttributes; ++i)
@@ -1207,7 +1206,7 @@ namespace MWScript
interpreter.installSegment5 (Compiler::Stats::opcodeUndoWerewolf, new OpSetWerewolf<ImplicitRef, false>);
interpreter.installSegment5 (Compiler::Stats::opcodeUndoWerewolfExplicit, new OpSetWerewolf<ExplicitRef, false>);
interpreter.installSegment5 (Compiler::Stats::opcodeSetWerewolfAcrobatics, new OpSetWerewolfAcrobatics<ImplicitRef>);
- interpreter.installSegment5 (Compiler::Stats::opcodeSetWerewolfAcrobaticsExplicit, new OpSetWerewolfAcrobatics<ExplicitRef>);
+ interpreter.installSegment5 (Compiler::Stats::opcodeSetWerewolfAcrobaticsExplicit, new OpSetWerewolfAcrobatics<ExplicitRef>);
}
}
}
diff --git a/apps/openmw/mwworld/class.cpp b/apps/openmw/mwworld/class.cpp
index c739ea831c..d3d1aff49b 100644
--- a/apps/openmw/mwworld/class.cpp
+++ b/apps/openmw/mwworld/class.cpp
@@ -132,6 +132,16 @@ namespace MWWorld
throw std::runtime_error ("class does not support unlocking");
}
+ void Class::setRemainingUsageTime (const Ptr& ptr, float duration) const
+ {
+ throw std::runtime_error ("class does not support time-based uses");
+ }
+
+ float Class::getRemainingUsageTime (const Ptr& ptr) const
+ {
+ throw std::runtime_error ("class does not support time-based uses");
+ }
+
std::string Class::getScript (const Ptr& ptr) const
{
return "";
@@ -167,6 +177,11 @@ namespace MWWorld
throw std::runtime_error ("class does not support enchanting");
}
+ float Class::getFallDamage(const MWWorld::Ptr &ptr, float fallHeight) const
+ {
+ return 0;
+ }
+
MWMechanics::Movement& Class::getMovementSettings (const Ptr& ptr) const
{
throw std::runtime_error ("movement settings not supported by class");
diff --git a/apps/openmw/mwworld/class.hpp b/apps/openmw/mwworld/class.hpp
index 28e37cbf3c..2db293e688 100644
--- a/apps/openmw/mwworld/class.hpp
+++ b/apps/openmw/mwworld/class.hpp
@@ -156,6 +156,14 @@ namespace MWWorld
virtual void unlock (const Ptr& ptr) const;
///< Unlock object (default implementation: throw an exception)
+ virtual void setRemainingUsageTime (const Ptr& ptr, float duration) const;
+ ///< Sets the remaining duration of the object, such as an equippable light
+ /// source. (default implementation: throw an exception)
+
+ virtual float getRemainingUsageTime (const Ptr& ptr) const;
+ ///< Returns the remaining duration of the object, such as an equippable light
+ /// source. (default implementation: throw an exception)
+
virtual std::string getScript (const Ptr& ptr) const;
///< Return name of the script attached to ptr (default implementation: return an empty
/// string).
@@ -175,6 +183,9 @@ namespace MWWorld
virtual float getJump(const MWWorld::Ptr &ptr) const;
///< Return jump velocity (not accounting for movement)
+ virtual float getFallDamage(const MWWorld::Ptr &ptr, float fallHeight) const;
+ ///< Return amount of health points lost when falling
+
virtual MWMechanics::Movement& getMovementSettings (const Ptr& ptr) const;
///< Return desired movement.
diff --git a/apps/openmw/mwworld/containerstore.cpp b/apps/openmw/mwworld/containerstore.cpp
index 9d111a5257..c6768f5fdd 100644
--- a/apps/openmw/mwworld/containerstore.cpp
+++ b/apps/openmw/mwworld/containerstore.cpp
@@ -80,7 +80,7 @@ MWWorld::ContainerStoreIterator MWWorld::ContainerStore::end()
bool MWWorld::ContainerStore::stacks(const Ptr& ptr1, const Ptr& ptr2)
{
/// \todo add current enchantment charge here when it is implemented
- if ( ptr1.getCellRef().mRefID == ptr2.getCellRef().mRefID
+ if ( Misc::StringUtils::ciEqual(ptr1.getCellRef().mRefID, ptr2.getCellRef().mRefID)
&& MWWorld::Class::get(ptr1).getScript(ptr1) == "" // item with a script never stacks
&& MWWorld::Class::get(ptr1).getEnchantment(ptr1) == "" // item with enchantment never stacks (we could revisit this later, but for now it makes selecting items in the spell window much easier)
&& ptr1.getCellRef().mOwner == ptr2.getCellRef().mOwner
diff --git a/apps/openmw/mwworld/contentloader.hpp b/apps/openmw/mwworld/contentloader.hpp
new file mode 100644
index 0000000000..46bd7d3f96
--- /dev/null
+++ b/apps/openmw/mwworld/contentloader.hpp
@@ -0,0 +1,36 @@
+#ifndef CONTENTLOADER_HPP
+#define CONTENTLOADER_HPP
+
+#include <iosfwd>
+#include <iostream>
+#include <boost/filesystem/path.hpp>
+
+#include "components/loadinglistener/loadinglistener.hpp"
+
+namespace MWWorld
+{
+
+struct ContentLoader
+{
+ ContentLoader(Loading::Listener& listener)
+ : mListener(listener)
+ {
+ }
+
+ virtual ~ContentLoader()
+ {
+ }
+
+ virtual void load(const boost::filesystem::path& filepath, int& index)
+ {
+ std::cout << "Loading content file " << filepath.string() << std::endl;
+ mListener.setLabel(filepath.string());
+ }
+
+ protected:
+ Loading::Listener& mListener;
+};
+
+} /* namespace MWWorld */
+
+#endif /* CONTENTLOADER_HPP */
diff --git a/apps/openmw/mwworld/esmloader.cpp b/apps/openmw/mwworld/esmloader.cpp
new file mode 100644
index 0000000000..1b8880d375
--- /dev/null
+++ b/apps/openmw/mwworld/esmloader.cpp
@@ -0,0 +1,31 @@
+#include "esmloader.hpp"
+#include "esmstore.hpp"
+
+#include "components/to_utf8/to_utf8.hpp"
+
+namespace MWWorld
+{
+
+EsmLoader::EsmLoader(MWWorld::ESMStore& store, std::vector<ESM::ESMReader>& readers,
+ ToUTF8::Utf8Encoder* encoder, Loading::Listener& listener)
+ : ContentLoader(listener)
+ , mStore(store)
+ , mEsm(readers)
+ , mEncoder(encoder)
+{
+}
+
+void EsmLoader::load(const boost::filesystem::path& filepath, int& index)
+{
+ ContentLoader::load(filepath.filename(), index);
+
+ ESM::ESMReader lEsm;
+ lEsm.setEncoder(mEncoder);
+ lEsm.setIndex(index);
+ lEsm.setGlobalReaderList(&mEsm);
+ lEsm.open(filepath.string());
+ mEsm[index] = lEsm;
+ mStore.load(mEsm[index], &mListener);
+}
+
+} /* namespace MWWorld */
diff --git a/apps/openmw/mwworld/esmloader.hpp b/apps/openmw/mwworld/esmloader.hpp
new file mode 100644
index 0000000000..d799c3f152
--- /dev/null
+++ b/apps/openmw/mwworld/esmloader.hpp
@@ -0,0 +1,34 @@
+#ifndef ESMLOADER_HPP
+#define ESMLOADER_HPP
+
+#include <vector>
+
+#include "contentloader.hpp"
+#include "components/esm/esmreader.hpp"
+
+namespace ToUTF8
+{
+ class Utf8Encoder;
+}
+
+namespace MWWorld
+{
+
+class ESMStore;
+
+struct EsmLoader : public ContentLoader
+{
+ EsmLoader(MWWorld::ESMStore& store, std::vector<ESM::ESMReader>& readers,
+ ToUTF8::Utf8Encoder* encoder, Loading::Listener& listener);
+
+ void load(const boost::filesystem::path& filepath, int& index);
+
+ private:
+ std::vector<ESM::ESMReader>& mEsm;
+ MWWorld::ESMStore& mStore;
+ ToUTF8::Utf8Encoder* mEncoder;
+};
+
+} /* namespace MWWorld */
+
+#endif // ESMLOADER_HPP
diff --git a/apps/openmw/mwworld/esmstore.cpp b/apps/openmw/mwworld/esmstore.cpp
index 7703f2d233..ab88787175 100644
--- a/apps/openmw/mwworld/esmstore.cpp
+++ b/apps/openmw/mwworld/esmstore.cpp
@@ -36,7 +36,7 @@ void ESMStore::load(ESM::ESMReader &esm, Loading::Listener* listener)
// all files/readers used by the engine. This will greaty accelerate
// refnumber mangling, as required for handling moved references.
int index = ~0;
- const std::vector<ESM::Header::MasterData> &masters = esm.getMasters();
+ const std::vector<ESM::Header::MasterData> &masters = esm.getGameFiles();
std::vector<ESM::ESMReader> *allPlugins = esm.getGlobalReaderList();
for (size_t j = 0; j < masters.size(); j++) {
ESM::Header::MasterData &mast = const_cast<ESM::Header::MasterData&>(masters[j]);
@@ -100,11 +100,7 @@ void ESMStore::load(ESM::ESMReader &esm, Loading::Listener* listener)
it->second->load(esm, id);
if (n.val==ESM::REC_DIAL) {
- // dirty hack, but it is better than non-const search()
- // or friends
- //dialogue = &mDialogs.mStatic.back();
dialogue = const_cast<ESM::Dialogue*>(mDialogs.find(id));
- assert (dialogue->mId == id);
} else {
dialogue = 0;
}
diff --git a/apps/openmw/mwworld/omwloader.cpp b/apps/openmw/mwworld/omwloader.cpp
new file mode 100644
index 0000000000..8562a4fe04
--- /dev/null
+++ b/apps/openmw/mwworld/omwloader.cpp
@@ -0,0 +1,17 @@
+#include "omwloader.hpp"
+
+namespace MWWorld
+{
+
+OmwLoader::OmwLoader(Loading::Listener& listener)
+ : ContentLoader(listener)
+{
+}
+
+void OmwLoader::load(const boost::filesystem::path& filepath, int& index)
+{
+ ContentLoader::load(filepath.filename(), index);
+}
+
+} /* namespace MWWorld */
+
diff --git a/apps/openmw/mwworld/omwloader.hpp b/apps/openmw/mwworld/omwloader.hpp
new file mode 100644
index 0000000000..cb9faa4303
--- /dev/null
+++ b/apps/openmw/mwworld/omwloader.hpp
@@ -0,0 +1,21 @@
+#ifndef OMWLOADER_HPP
+#define OMWLOADER_HPP
+
+#include "contentloader.hpp"
+
+namespace MWWorld
+{
+
+/**
+ * @brief Placeholder for real OpenMW content loader
+ */
+struct OmwLoader : public ContentLoader
+{
+ OmwLoader(Loading::Listener& listener);
+
+ void load(const boost::filesystem::path& filepath, int& index);
+};
+
+} /* namespace MWWorld */
+
+#endif /* OMWLOADER_HPP */
diff --git a/apps/openmw/mwworld/store.hpp b/apps/openmw/mwworld/store.hpp
index 2ee23dbd61..90452f6614 100644
--- a/apps/openmw/mwworld/store.hpp
+++ b/apps/openmw/mwworld/store.hpp
@@ -656,26 +656,38 @@ namespace MWWorld
return iterator(mSharedExt.end());
}
- /// \todo implement appropriate index
+ // Return the northernmost cell in the easternmost column.
const ESM::Cell *searchExtByName(const std::string &id) const {
+ ESM::Cell *cell = 0;
std::vector<ESM::Cell *>::const_iterator it = mSharedExt.begin();
for (; it != mSharedExt.end(); ++it) {
if (Misc::StringUtils::ciEqual((*it)->mName, id)) {
- return *it;
+ if ( cell == 0 ||
+ ( (*it)->mData.mX > cell->mData.mX ) ||
+ ( (*it)->mData.mX == cell->mData.mX && (*it)->mData.mY > cell->mData.mY ) )
+ {
+ cell = *it;
+ }
}
}
- return 0;
+ return cell;
}
- /// \todo implement appropriate index
+ // Return the northernmost cell in the easternmost column.
const ESM::Cell *searchExtByRegion(const std::string &id) const {
+ ESM::Cell *cell = 0;
std::vector<ESM::Cell *>::const_iterator it = mSharedExt.begin();
for (; it != mSharedExt.end(); ++it) {
if (Misc::StringUtils::ciEqual((*it)->mRegion, id)) {
- return *it;
+ if ( cell == 0 ||
+ ( (*it)->mData.mX > cell->mData.mX ) ||
+ ( (*it)->mData.mX == cell->mData.mX && (*it)->mData.mY > cell->mData.mY ) )
+ {
+ cell = *it;
+ }
}
}
- return 0;
+ return cell;
}
size_t getSize() const {
diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp
index eac0a39776..6a4a380d65 100644
--- a/apps/openmw/mwworld/worldimp.cpp
+++ b/apps/openmw/mwworld/worldimp.cpp
@@ -1,4 +1,11 @@
#include "worldimp.hpp"
+#ifdef _WIN32
+#include <boost/tr1/tr1/unordered_map>
+#elif defined HAVE_UNORDERED_MAP
+#include <unordered_map>
+#else
+#include <tr1/unordered_map>
+#endif
#include <OgreSceneNode.h>
@@ -31,6 +38,10 @@
#include "containerstore.hpp"
#include "inventorystore.hpp"
+#include "contentloader.hpp"
+#include "esmloader.hpp"
+#include "omwloader.hpp"
+
using namespace Ogre;
namespace
@@ -80,6 +91,38 @@ namespace
namespace MWWorld
{
+ struct GameContentLoader : public ContentLoader
+ {
+ GameContentLoader(Loading::Listener& listener)
+ : ContentLoader(listener)
+ {
+ }
+
+ bool addLoader(const std::string& extension, ContentLoader* loader)
+ {
+ return mLoaders.insert(std::make_pair(extension, loader)).second;
+ }
+
+ void load(const boost::filesystem::path& filepath, int& index)
+ {
+ LoadersContainer::iterator it(mLoaders.find(filepath.extension().string()));
+ if (it != mLoaders.end())
+ {
+ it->second->load(filepath, index);
+ }
+ else
+ {
+ std::string msg("Cannot load file: ");
+ msg += filepath.string();
+ throw std::runtime_error(msg.c_str());
+ }
+ }
+
+ private:
+ typedef std::tr1::unordered_map<std::string, ContentLoader*> LoadersContainer;
+ LoadersContainer mLoaders;
+ };
+
Ptr World::getPtrViaHandle (const std::string& handle, Ptr::CellStore& cell)
{
if (MWWorld::LiveCellRef<ESM::Activator> *ref =
@@ -163,14 +206,14 @@ namespace MWWorld
World::World (OEngine::Render::OgreRenderer& renderer,
const Files::Collections& fileCollections,
- const std::vector<std::string>& master, const std::vector<std::string>& plugins,
+ const std::vector<std::string>& contentFiles,
const boost::filesystem::path& resDir, const boost::filesystem::path& cacheDir,
ToUTF8::Utf8Encoder* encoder, const std::map<std::string,std::string>& fallbackMap, int mActivationDistanceOverride)
: mPlayer (0), mLocalScripts (mStore), mGlobalVariables (0),
mSky (true), mCells (mStore, mEsm),
mActivationDistanceOverride (mActivationDistanceOverride),
mFallback(fallbackMap), mPlayIntro(0), mTeleportEnabled(true),
- mFacedDistance(FLT_MAX)
+ mFacedDistance(FLT_MAX), mGodMode(false)
{
mPhysics = new PhysicsSystem(renderer);
mPhysEngine = mPhysics->getEngine();
@@ -181,52 +224,30 @@ namespace MWWorld
mWeatherManager = new MWWorld::WeatherManager(mRendering,&mFallback);
- int idx = 0;
// NOTE: We might need to reserve one more for the running game / save.
- mEsm.resize(master.size() + plugins.size());
+ mEsm.resize(contentFiles.size());
Loading::Listener* listener = MWBase::Environment::get().getWindowManager()->getLoadingScreen();
listener->loadingOn();
- for (std::vector<std::string>::size_type i = 0; i < master.size(); i++, idx++)
- {
- boost::filesystem::path masterPath (fileCollections.getCollection (".esm").getPath (master[i]));
-
- std::cout << "Loading ESM " << masterPath.string() << "\n";
- listener->setLabel(masterPath.filename().string());
- // This parses the ESM file
- ESM::ESMReader lEsm;
- lEsm.setEncoder(encoder);
- lEsm.setIndex(idx);
- lEsm.setGlobalReaderList(&mEsm);
- lEsm.open (masterPath.string());
- mEsm[idx] = lEsm;
- mStore.load (mEsm[idx], listener);
- }
+ GameContentLoader gameContentLoader(*listener);
+ EsmLoader esmLoader(mStore, mEsm, encoder, *listener);
+ OmwLoader omwLoader(*listener);
- for (std::vector<std::string>::size_type i = 0; i < plugins.size(); i++, idx++)
- {
- boost::filesystem::path pluginPath (fileCollections.getCollection (".esp").getPath (plugins[i]));
+ gameContentLoader.addLoader(".esm", &esmLoader);
+ gameContentLoader.addLoader(".esp", &esmLoader);
+ gameContentLoader.addLoader(".omwgame", &omwLoader);
+ gameContentLoader.addLoader(".omwaddon", &omwLoader);
- std::cout << "Loading ESP " << pluginPath.string() << "\n";
- listener->setLabel(pluginPath.filename().string());
+ loadContentFiles(fileCollections, contentFiles, gameContentLoader);
- // This parses the ESP file
- ESM::ESMReader lEsm;
- lEsm.setEncoder(encoder);
- lEsm.setIndex(idx);
- lEsm.setGlobalReaderList(&mEsm);
- lEsm.open (pluginPath.string());
- mEsm[idx] = lEsm;
- mStore.load (mEsm[idx], listener);
- }
listener->loadingOff();
// insert records that may not be present in all versions of MW
if (mEsm[0].getFormat() == 0)
ensureNeededRecords();
- mStore.movePlayerRecord();
mStore.setUp();
+ mStore.movePlayerRecord();
mGlobalVariables = new Globals (mStore);
@@ -1160,7 +1181,7 @@ namespace MWWorld
bool World::toggleCollisionMode()
{
- return mPhysics->toggleCollisionMode();;
+ return mPhysics->toggleCollisionMode();
}
bool World::toggleRenderMode (RenderMode mode)
@@ -1582,6 +1603,19 @@ namespace MWWorld
return false;
}
+ bool
+ World::isSlowFalling(const MWWorld::Ptr &ptr) const
+ {
+ if(!ptr.getClass().isActor())
+ return false;
+
+ const MWMechanics::CreatureStats &stats = ptr.getClass().getCreatureStats(ptr);
+ if(stats.getMagicEffects().get(MWMechanics::EffectKey(ESM::MagicEffect::SlowFall)).mMagnitude > 0)
+ return true;
+
+ return false;
+ }
+
bool World::isSubmerged(const MWWorld::Ptr &object) const
{
float *fpos = object.getRefData().getPosition().pos;
@@ -1877,6 +1911,16 @@ namespace MWWorld
return mTeleportEnabled;
}
+ void World::enableLevitation(bool enable)
+ {
+ mLevitationEnabled = enable;
+ }
+
+ bool World::isLevitationEnabled() const
+ {
+ return mLevitationEnabled;
+ }
+
void World::setWerewolf(const MWWorld::Ptr& actor, bool werewolf)
{
MWMechanics::NpcStats& npcStats = Class::get(actor).getNpcStats(actor);
@@ -1948,4 +1992,31 @@ namespace MWWorld
stats.getSkill(ESM::Skill::Acrobatics).setModified(gmst.find("fWerewolfAcrobatics")->getFloat(), 0);
}
+ bool World::getGodModeState()
+ {
+ return mGodMode;
+ }
+
+ bool World::toggleGodMode()
+ {
+ mGodMode = !mGodMode;
+
+ return mGodMode;
+ }
+
+ void World::loadContentFiles(const Files::Collections& fileCollections,
+ const std::vector<std::string>& content, ContentLoader& contentLoader)
+ {
+ std::vector<std::string>::const_iterator it(content.begin());
+ std::vector<std::string>::const_iterator end(content.end());
+ for (int idx = 0; it != end; ++it, ++idx)
+ {
+ boost::filesystem::path filename(*it);
+ const Files::MultiDirCollection& col = fileCollections.getCollection(filename.extension().string());
+ if (col.doesExist(*it))
+ {
+ contentLoader.load(col.getPath(*it), idx);
+ }
+ }
+ }
}
diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp
index 71391239b3..aadf7ce981 100644
--- a/apps/openmw/mwworld/worldimp.hpp
+++ b/apps/openmw/mwworld/worldimp.hpp
@@ -14,6 +14,8 @@
#include "../mwbase/world.hpp"
+#include "contentloader.hpp"
+
namespace Ogre
{
class Vector3;
@@ -41,6 +43,8 @@ namespace MWRender
class Animation;
}
+struct ContentLoader;
+
namespace MWWorld
{
class WeatherManager;
@@ -68,6 +72,8 @@ namespace MWWorld
OEngine::Physic::PhysicEngine* mPhysEngine;
+ bool mGodMode;
+
// not implemented
World (const World&);
World& operator= (const World&);
@@ -111,15 +117,25 @@ namespace MWWorld
void ensureNeededRecords();
+ /**
+ * @brief loadContentFiles - Loads content files (esm,esp,omwgame,omwaddon)
+ * @param fileCollections- Container which holds content file names and their paths
+ * @param content - Container which holds content file names
+ * @param contentLoader -
+ */
+ void loadContentFiles(const Files::Collections& fileCollections,
+ const std::vector<std::string>& content, ContentLoader& contentLoader);
+
int mPlayIntro;
bool mTeleportEnabled;
+ bool mLevitationEnabled;
public:
World (OEngine::Render::OgreRenderer& renderer,
const Files::Collections& fileCollections,
- const std::vector<std::string>& master, const std::vector<std::string>& plugins,
+ const std::vector<std::string>& contentFiles,
const boost::filesystem::path& resDir, const boost::filesystem::path& cacheDir,
ToUTF8::Utf8Encoder* encoder, const std::map<std::string,std::string>& fallbackMap, int mActivationDistanceOverride);
@@ -353,6 +369,7 @@ namespace MWWorld
virtual void processChangedSettings(const Settings::CategorySettingVector& settings);
virtual bool isFlying(const MWWorld::Ptr &ptr) const;
+ virtual bool isSlowFalling(const MWWorld::Ptr &ptr) const;
///Is the head of the creature underwater?
virtual bool isSubmerged(const MWWorld::Ptr &object) const;
virtual bool isSwimming(const MWWorld::Ptr &object) const;
@@ -436,9 +453,19 @@ namespace MWWorld
/// Returns true if teleport spell effects are allowed.
virtual bool isTeleportingEnabled() const;
+ /// Enables or disables use of levitation spell effect.
+ virtual void enableLevitation(bool enable);
+
+ /// Returns true if levitation spell effect is allowed.
+ virtual bool isLevitationEnabled() const;
+
virtual void setWerewolf(const MWWorld::Ptr& actor, bool werewolf);
virtual void applyWerewolfAcrobatics(const MWWorld::Ptr& actor);
+
+ virtual bool getGodModeState();
+
+ virtual bool toggleGodMode();
};
}
diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt
index 04423dc6f0..acb70b04db 100644
--- a/components/CMakeLists.txt
+++ b/components/CMakeLists.txt
@@ -1,5 +1,5 @@
project (Components)
-
+set (CMAKE_BUILD_TYPE DEBUG)
# source files
add_component_dir (settings
@@ -74,21 +74,25 @@ add_component_dir (loadinglistener
loadinglistener
)
+set (ESM_UI ${CMAKE_SOURCE_DIR}/files/ui/contentselector.ui
+ )
find_package(Qt4 COMPONENTS QtCore QtGui)
if(QT_QTGUI_LIBRARY AND QT_QTCORE_LIBRARY)
- add_component_qt_dir (fileorderlist
- model/modelitem model/datafilesmodel model/pluginsproxymodel model/esm/esmfile
- utils/profilescombobox utils/comboboxlineedit utils/lineedit utils/naturalsort
+ add_component_qt_dir (contentselector
+ model/modelitem model/esmfile
+ model/naturalsort model/contentmodel
+ view/combobox view/contentselector
)
include(${QT_USE_FILE})
+ QT4_WRAP_UI(ESM_UI_HDR ${ESM_UI})
QT4_WRAP_CPP(MOC_SRCS ${COMPONENT_MOC_FILES})
endif(QT_QTGUI_LIBRARY AND QT_QTCORE_LIBRARY)
-include_directories(${BULLET_INCLUDE_DIRS})
+include_directories(${BULLET_INCLUDE_DIRS} ${CMAKE_CURRENT_BINARY_DIR})
-add_library(components STATIC ${COMPONENT_FILES} ${MOC_SRCS})
+add_library(components STATIC ${COMPONENT_FILES} ${MOC_SRCS} ${ESM_UI_HDR})
target_link_libraries(components ${Boost_LIBRARIES} ${OGRE_LIBRARIES})
diff --git a/components/bsa/tests/.gitignore b/components/bsa/tests/.gitignore
new file mode 100644
index 0000000000..e2f2f332df
--- /dev/null
+++ b/components/bsa/tests/.gitignore
@@ -0,0 +1,3 @@
+*_test
+bsatool
+*.bsa
diff --git a/components/compiler/extensions0.cpp b/components/compiler/extensions0.cpp
index 9e0c36825a..65f6e112a3 100644
--- a/components/compiler/extensions0.cpp
+++ b/components/compiler/extensions0.cpp
@@ -258,6 +258,10 @@ namespace Compiler
extensions.registerInstruction ("enableteleporting", "", opcodeEnableTeleporting);
extensions.registerInstruction ("showvars", "", opcodeShowVars, opcodeShowVarsExplicit);
extensions.registerInstruction ("sv", "", opcodeShowVars, opcodeShowVarsExplicit);
+ extensions.registerInstruction("tgm", "", opcodeToggleGodMode);
+ extensions.registerInstruction("togglegodmode", "", opcodeToggleGodMode);
+ extensions.registerInstruction ("disablelevitation", "", opcodeDisableLevitation);
+ extensions.registerInstruction ("enablelevitation", "", opcodeEnableLevitation);
}
}
diff --git a/components/compiler/opcodes.hpp b/components/compiler/opcodes.hpp
index c4e2c1bc6b..aca24e0d30 100644
--- a/components/compiler/opcodes.hpp
+++ b/components/compiler/opcodes.hpp
@@ -221,6 +221,9 @@ namespace Compiler
const int opcodeEnableTeleporting = 0x2000216;
const int opcodeShowVars = 0x200021d;
const int opcodeShowVarsExplicit = 0x200021e;
+ const int opcodeToggleGodMode = 0x200021f;
+ const int opcodeDisableLevitation = 0x2000220;
+ const int opcodeEnableLevitation = 0x2000221;
}
namespace Sky
diff --git a/components/contentselector/model/contentmodel.cpp b/components/contentselector/model/contentmodel.cpp
new file mode 100644
index 0000000000..5f3575eb40
--- /dev/null
+++ b/components/contentselector/model/contentmodel.cpp
@@ -0,0 +1,616 @@
+#include "contentmodel.hpp"
+#include "esmfile.hpp"
+
+#include <QDir>
+#include <QTextCodec>
+#include <QDebug>
+
+#include "components/esm/esmreader.hpp"
+
+ContentSelectorModel::ContentModel::ContentModel(QObject *parent) :
+ QAbstractTableModel(parent),
+ mMimeType ("application/omwcontent"),
+ mMimeTypes (QStringList() << mMimeType),
+ mColumnCount (1),
+ mDragDropFlags (Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled),
+ mDropActions (Qt::CopyAction | Qt::MoveAction)
+{
+ setEncoding ("win1252");
+ uncheckAll();
+}
+
+void ContentSelectorModel::ContentModel::setEncoding(const QString &encoding)
+{
+ if (encoding == QLatin1String("win1252"))
+ mCodec = QTextCodec::codecForName("windows-1252");
+
+ else if (encoding == QLatin1String("win1251"))
+ mCodec = QTextCodec::codecForName("windows-1251");
+
+ else if (encoding == QLatin1String("win1250"))
+ mCodec = QTextCodec::codecForName("windows-1250");
+
+ else
+ return; // This should never happen;
+}
+
+int ContentSelectorModel::ContentModel::columnCount(const QModelIndex &parent) const
+{
+ if (parent.isValid())
+ return 0;
+
+ return mColumnCount;
+}
+
+int ContentSelectorModel::ContentModel::rowCount(const QModelIndex &parent) const
+{
+ if(parent.isValid())
+ return 0;
+
+ return mFiles.size();
+}
+
+const ContentSelectorModel::EsmFile *ContentSelectorModel::ContentModel::item(int row) const
+{
+ if (row >= 0 && row < mFiles.size())
+ return mFiles.at(row);
+
+ return 0;
+}
+
+ContentSelectorModel::EsmFile *ContentSelectorModel::ContentModel::item(int row)
+{
+ if (row >= 0 && row < mFiles.count())
+ return mFiles.at(row);
+
+ return 0;
+}
+const ContentSelectorModel::EsmFile *ContentSelectorModel::ContentModel::item(const QString &name) const
+{
+ EsmFile::FileProperty fp = EsmFile::FileProperty_FileName;
+
+ if (name.contains ('/'))
+ fp = EsmFile::FileProperty_FilePath;
+
+ foreach (const EsmFile *file, mFiles)
+ {
+ if (name == file->fileProperty (fp).toString())
+ return file;
+ }
+ return 0;
+}
+
+QModelIndex ContentSelectorModel::ContentModel::indexFromItem(const EsmFile *item) const
+{
+ //workaround: non-const pointer cast for calls from outside contentmodel/contentselector
+ EsmFile *non_const_file_ptr = const_cast<EsmFile *>(item);
+
+ if (item)
+ return index(mFiles.indexOf(non_const_file_ptr),0);
+
+ return QModelIndex();
+}
+
+Qt::ItemFlags ContentSelectorModel::ContentModel::flags(const QModelIndex &index) const
+{
+ if (!index.isValid())
+ return Qt::NoItemFlags;
+
+ const EsmFile *file = item(index.row());
+
+ if (!file)
+ return Qt::NoItemFlags;
+
+ //game files can always be checked
+ if (file->isGameFile())
+ return Qt::ItemIsEnabled | Qt::ItemIsSelectable;
+
+ Qt::ItemFlags returnFlags;
+ bool allDependenciesFound = true;
+ bool gamefileChecked = false;
+
+ //addon can be checked if its gamefile is and all other dependencies exist
+ foreach (const QString &fileName, file->gameFiles())
+ {
+ bool depFound = false;
+ foreach (EsmFile *dependency, mFiles)
+ {
+ //compare filenames only. Multiple instances
+ //of the filename (with different paths) is not relevant here.
+ depFound = (dependency->fileName() == fileName);
+
+ if (!depFound)
+ continue;
+
+ if (!gamefileChecked)
+ {
+ if (isChecked (dependency->filePath()))
+ gamefileChecked = (dependency->isGameFile());
+ }
+
+ // force it to iterate all files in cases where the current
+ // dependency is a game file to ensure that a later duplicate
+ // game file is / is not checked.
+ // (i.e., break only if it's not a gamefile or the game file has been checked previously)
+ if (gamefileChecked || !(dependency->isGameFile()))
+ break;
+ }
+
+ allDependenciesFound = allDependenciesFound && depFound;
+ }
+
+ if (gamefileChecked)
+ {
+ if (allDependenciesFound)
+ returnFlags = returnFlags | Qt::ItemIsEnabled | Qt::ItemIsSelectable | mDragDropFlags;
+ else
+ returnFlags = Qt::ItemIsSelectable;
+ }
+
+ return returnFlags;
+}
+
+QVariant ContentSelectorModel::ContentModel::data(const QModelIndex &index, int role) const
+{
+ if (!index.isValid())
+ return QVariant();
+
+ if (index.row() >= mFiles.size())
+ return QVariant();
+
+ const EsmFile *file = item(index.row());
+
+ if (!file)
+ return QVariant();
+
+ const int column = index.column();
+
+ switch (role)
+ {
+ case Qt::EditRole:
+ case Qt::DisplayRole:
+ {
+ if (column >=0 && column <=EsmFile::FileProperty_GameFile)
+ return file->fileProperty(static_cast<const EsmFile::FileProperty>(column));
+
+ return QVariant();
+ break;
+ }
+
+ case Qt::TextAlignmentRole:
+ {
+ switch (column)
+ {
+ case 0:
+ case 1:
+ return Qt::AlignLeft + Qt::AlignVCenter;
+ case 2:
+ case 3:
+ return Qt::AlignRight + Qt::AlignVCenter;
+ default:
+ return Qt::AlignLeft + Qt::AlignVCenter;
+ }
+ return QVariant();
+ break;
+ }
+
+ case Qt::ToolTipRole:
+ {
+ if (column != 0)
+ return QVariant();
+
+ return file->toolTip();
+ break;
+ }
+
+ case Qt::CheckStateRole:
+ {
+ if (!file->isGameFile())
+ return isChecked(file->filePath());
+ break;
+ }
+
+ case Qt::UserRole:
+ {
+ if (file->isGameFile())
+ return ContentType_GameFile;
+ else
+ if (flags(index))
+ return ContentType_Addon;
+
+ break;
+ }
+
+ case Qt::UserRole + 1:
+ return isChecked(file->filePath());
+ break;
+ }
+ return QVariant();
+}
+
+bool ContentSelectorModel::ContentModel::setData(const QModelIndex &index, const QVariant &value, int role)
+{
+ if(!index.isValid())
+ return false;
+
+ EsmFile *file = item(index.row());
+ QString fileName = file->filePath();
+ bool success = false;
+
+ switch(role)
+ {
+ case Qt::EditRole:
+ {
+ QStringList list = value.toStringList();
+
+ for (int i = 0; i < EsmFile::FileProperty_GameFile; i++)
+ file->setFileProperty(static_cast<EsmFile::FileProperty>(i), list.at(i));
+
+ for (int i = EsmFile::FileProperty_GameFile; i < list.size(); i++)
+ file->setFileProperty (EsmFile::FileProperty_GameFile, list.at(i));
+
+ emit dataChanged(index, index);
+
+ success = true;
+ }
+ break;
+
+ case Qt::UserRole+1:
+ {
+ success = (flags (index) & Qt::ItemIsEnabled);
+
+ if (success)
+ {
+ success = setCheckState(fileName, value.toBool());
+ emit dataChanged(index, index);
+ }
+ }
+ break;
+
+ case Qt::CheckStateRole:
+ {
+ int checkValue = value.toInt();
+ bool success = false;
+ bool setState = false;
+ if ((checkValue==Qt::Checked) && !isChecked(fileName))
+ {
+ setState = true;
+ success = true;
+ }
+ else if ((checkValue == Qt::Checked) && isChecked (fileName))
+ setState = true;
+ else if (checkValue == Qt::Unchecked)
+ setState = true;
+
+ if (setState)
+ {
+ setCheckState(fileName, success);
+ emit dataChanged(index, index);
+
+ }
+ else
+ return success;
+
+
+ foreach (EsmFile *file, mFiles)
+ {
+ if (file->gameFiles().contains(fileName))
+ {
+ QModelIndex idx = indexFromItem(file);
+ emit dataChanged(idx, idx);
+ }
+ }
+
+ success = true;
+ }
+ break;
+ }
+
+ return success;
+}
+
+bool ContentSelectorModel::ContentModel::insertRows(int position, int rows, const QModelIndex &parent)
+{
+ if (parent.isValid())
+ return false;
+
+ beginInsertRows(parent, position, position+rows-1);
+ {
+ for (int row = 0; row < rows; ++row)
+ mFiles.insert(position, new EsmFile);
+
+ } endInsertRows();
+
+ return true;
+}
+
+bool ContentSelectorModel::ContentModel::removeRows(int position, int rows, const QModelIndex &parent)
+{
+ if (parent.isValid())
+ return false;
+
+ beginRemoveRows(parent, position, position+rows-1);
+ {
+ for (int row = 0; row < rows; ++row)
+ delete mFiles.takeAt(position);
+
+ } endRemoveRows();
+
+ return true;
+}
+
+Qt::DropActions ContentSelectorModel::ContentModel::supportedDropActions() const
+{
+ return mDropActions;
+}
+
+QStringList ContentSelectorModel::ContentModel::mimeTypes() const
+{
+ return mMimeTypes;
+}
+
+QMimeData *ContentSelectorModel::ContentModel::mimeData(const QModelIndexList &indexes) const
+{
+ QByteArray encodedData;
+
+ foreach (const QModelIndex &index, indexes)
+ {
+ if (!index.isValid())
+ continue;
+
+ encodedData.append(item(index.row())->encodedData());
+ }
+
+ QMimeData *mimeData = new QMimeData();
+ mimeData->setData(mMimeType, encodedData);
+
+ return mimeData;
+}
+
+bool ContentSelectorModel::ContentModel::dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent)
+{
+ if (action == Qt::IgnoreAction)
+ return true;
+
+ if (column > 0)
+ return false;
+
+ if (!data->hasFormat(mMimeType))
+ return false;
+
+ int beginRow = rowCount();
+
+ if (row != -1)
+ beginRow = row;
+
+ else if (parent.isValid())
+ beginRow = parent.row();
+
+ QByteArray encodedData = data->data(mMimeType);
+ QDataStream stream(&encodedData, QIODevice::ReadOnly);
+
+ while (!stream.atEnd())
+ {
+
+ QString value;
+ QStringList values;
+ QStringList gamefiles;
+
+ for (int i = 0; i < EsmFile::FileProperty_GameFile; ++i)
+ {
+ stream >> value;
+ values << value;
+ }
+
+ stream >> gamefiles;
+
+ insertRows(beginRow, 1);
+
+ QModelIndex idx = index(beginRow++, 0, QModelIndex());
+ setData(idx, QStringList() << values << gamefiles, Qt::EditRole);
+ }
+
+ return true;
+}
+
+void ContentSelectorModel::ContentModel::addFile(EsmFile *file)
+{
+ beginInsertRows(QModelIndex(), mFiles.count(), mFiles.count());
+ mFiles.append(file);
+ endInsertRows();
+
+ QModelIndex idx = index (mFiles.size() - 2, 0, QModelIndex());
+
+ emit dataChanged (idx, idx);
+}
+
+void ContentSelectorModel::ContentModel::addFiles(const QString &path)
+{
+ QDir dir(path);
+ QStringList filters;
+ filters << "*.esp" << "*.esm" << "*.omwgame" << "*.omwaddon";
+ dir.setNameFilters(filters);
+
+ QTextCodec *codec = QTextCodec::codecForName("UTF8");
+
+ // Create a decoder for non-latin characters in esx metadata
+ QTextDecoder *decoder = codec->makeDecoder();
+
+ foreach (const QString &path, dir.entryList())
+ {
+ QFileInfo info(dir.absoluteFilePath(path));
+ EsmFile *file = new EsmFile(path);
+
+ try {
+ ESM::ESMReader fileReader;
+ ToUTF8::Utf8Encoder encoder =
+ ToUTF8::calculateEncoding(QString(mCodec->name()).toStdString());
+ fileReader.setEncoder(&encoder);
+ fileReader.open(dir.absoluteFilePath(path).toStdString());
+
+ foreach (const ESM::Header::MasterData &item, fileReader.getGameFiles())
+ file->addGameFile(QString::fromStdString(item.name));
+
+ file->setAuthor (decoder->toUnicode(fileReader.getAuthor().c_str()));
+ file->setDate (info.lastModified());
+ file->setFormat (fileReader.getFormat());
+ file->setFilePath (info.absoluteFilePath());
+ file->setDescription(decoder->toUnicode(fileReader.getDesc().c_str()));
+
+
+ // Put the file in the table
+ if (item(file->filePath()) == 0)
+ addFile(file);
+
+ } catch(std::runtime_error &e) {
+ // An error occurred while reading the .esp
+ qWarning() << "Error reading addon file: " << e.what();
+ continue;
+ }
+
+ }
+
+ delete decoder;
+
+ sortFiles();
+}
+
+void ContentSelectorModel::ContentModel::sortFiles()
+{
+ //first, sort the model such that all dependencies are ordered upstream (gamefile) first.
+ bool movedFiles = true;
+ int fileCount = mFiles.size();
+
+ //Dependency sort
+ //iterate until no sorting of files occurs
+ while (movedFiles)
+ {
+ movedFiles = false;
+ //iterate each file, obtaining a reference to it's gamefiles list
+ for (int i = 0; i < fileCount; i++)
+ {
+ QModelIndex idx1 = index (i, 0, QModelIndex());
+ const QStringList &gamefiles = mFiles.at(i)->gameFiles();
+ //iterate each file after the current file, verifying that none of it's
+ //dependencies appear.
+ for (int j = i + 1; j < fileCount; j++)
+ {
+ if (gamefiles.contains(mFiles.at(j)->fileName()))
+ {
+ mFiles.move(j, i);
+
+ QModelIndex idx2 = index (j, 0, QModelIndex());
+
+ emit dataChanged (idx1, idx2);
+
+ movedFiles = true;
+ }
+ }
+ if (movedFiles)
+ break;
+ }
+ }
+}
+
+bool ContentSelectorModel::ContentModel::isChecked(const QString& name) const
+{
+ if (mCheckStates.contains(name))
+ return (mCheckStates[name] == Qt::Checked);
+
+ return false;
+}
+
+bool ContentSelectorModel::ContentModel::isEnabled (QModelIndex index) const
+{
+ return (flags(index) & Qt::ItemIsEnabled);
+}
+
+void ContentSelectorModel::ContentModel::setCheckStates (const QStringList &fileList, bool isChecked)
+{
+ foreach (const QString &file, fileList)
+ {
+ setCheckState (file, isChecked);
+ }
+}
+
+void ContentSelectorModel::ContentModel::refreshModel()
+{
+ emit dataChanged (index(0,0), index(rowCount()-1,0));
+}
+
+bool ContentSelectorModel::ContentModel::setCheckState(const QString &name, bool checkState)
+{
+ if (name.isEmpty())
+ return false;
+
+ const EsmFile *file = item(name);
+
+ if (!file)
+ return false;
+
+ Qt::CheckState state = Qt::Unchecked;
+
+ if (checkState)
+ state = Qt::Checked;
+
+ mCheckStates[name] = state;
+ emit dataChanged(indexFromItem(item(name)), indexFromItem(item(name)));
+
+ if (file->isGameFile())
+ refreshModel();
+
+ //if we're checking an item, ensure all "upstream" files (dependencies) are checked as well.
+ if (state == Qt::Checked)
+ {
+ foreach (QString upstreamName, file->gameFiles())
+ {
+ const EsmFile *upstreamFile = item(upstreamName);
+
+ if (!upstreamFile)
+ continue;
+
+ if (!isChecked(upstreamFile->filePath()))
+ mCheckStates[upstreamFile->filePath()] = Qt::Checked;
+
+ emit dataChanged(indexFromItem(upstreamFile), indexFromItem(upstreamFile));
+
+ }
+ }
+ //otherwise, if we're unchecking an item (or the file is a game file) ensure all downstream files are unchecked.
+ if (state == Qt::Unchecked)
+ {
+ foreach (const EsmFile *downstreamFile, mFiles)
+ {
+ if (downstreamFile->gameFiles().contains(name))
+ {
+ if (mCheckStates.contains(downstreamFile->filePath()))
+ mCheckStates[downstreamFile->filePath()] = Qt::Unchecked;
+
+ emit dataChanged(indexFromItem(downstreamFile), indexFromItem(downstreamFile));
+ }
+ }
+ }
+
+ return true;
+}
+
+ContentSelectorModel::ContentFileList ContentSelectorModel::ContentModel::checkedItems() const
+{
+ ContentFileList list;
+
+ // TODO:
+ // First search for game files and next addons,
+ // so we get more or less correct game files vs addons order.
+ foreach (EsmFile *file, mFiles)
+ if (isChecked(file->filePath()))
+ list << file;
+
+ return list;
+}
+
+void ContentSelectorModel::ContentModel::uncheckAll()
+{
+ emit layoutAboutToBeChanged();
+ mCheckStates.clear();
+ emit layoutChanged();
+}
diff --git a/components/contentselector/model/contentmodel.hpp b/components/contentselector/model/contentmodel.hpp
new file mode 100644
index 0000000000..8c8c2124bc
--- /dev/null
+++ b/components/contentselector/model/contentmodel.hpp
@@ -0,0 +1,77 @@
+#ifndef CONTENTMODEL_HPP
+#define CONTENTMODEL_HPP
+
+#include <QAbstractTableModel>
+#include <QStringList>
+
+namespace ContentSelectorModel
+{
+ class EsmFile;
+
+ typedef QList<EsmFile *> ContentFileList;
+
+ enum ContentType
+ {
+ ContentType_GameFile,
+ ContentType_Addon
+ };
+
+ class ContentModel : public QAbstractTableModel
+ {
+ Q_OBJECT
+ public:
+ explicit ContentModel(QObject *parent = 0);
+
+ void setEncoding(const QString &encoding);
+
+ int rowCount(const QModelIndex &parent = QModelIndex()) const;
+ int columnCount(const QModelIndex &parent = QModelIndex()) const;
+
+ QVariant data(const QModelIndex &index, int role) const;
+ Qt::ItemFlags flags(const QModelIndex &index) const;
+ bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole);
+
+ bool insertRows(int position, int rows, const QModelIndex &index = QModelIndex());
+ bool removeRows(int position, int rows, const QModelIndex &index = QModelIndex());
+
+ Qt::DropActions supportedDropActions() const;
+ QStringList mimeTypes() const;
+ QMimeData *mimeData(const QModelIndexList &indexes) const;
+ bool dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent);
+
+ void addFiles(const QString &path);
+
+ QModelIndex indexFromItem(const EsmFile *item) const;
+ const EsmFile *item(const QString &name) const;
+
+ bool isEnabled (QModelIndex index) const;
+ bool isChecked(const QString &name) const;
+ bool setCheckState(const QString &name, bool isChecked);
+ void setCheckStates (const QStringList &fileList, bool isChecked);
+ ContentFileList checkedItems() const;
+ void uncheckAll();
+
+ void refreshModel();
+
+ private:
+
+ void addFile(EsmFile *file);
+ const EsmFile *item(int row) const;
+ EsmFile *item(int row);
+
+ void sortFiles();
+
+ ContentFileList mFiles;
+ QHash<QString, Qt::CheckState> mCheckStates;
+ QTextCodec *mCodec;
+
+ public:
+
+ QString mMimeType;
+ QStringList mMimeTypes;
+ int mColumnCount;
+ Qt::ItemFlags mDragDropFlags;
+ Qt::DropActions mDropActions;
+ };
+}
+#endif // CONTENTMODEL_HPP
diff --git a/components/contentselector/model/esmfile.cpp b/components/contentselector/model/esmfile.cpp
new file mode 100644
index 0000000000..a0a09105a7
--- /dev/null
+++ b/components/contentselector/model/esmfile.cpp
@@ -0,0 +1,137 @@
+#include "esmfile.hpp"
+
+#include <QMimeData>
+#include <QDataStream>
+
+int ContentSelectorModel::EsmFile::sPropertyCount = 7;
+QString ContentSelectorModel::EsmFile::sToolTip = QString("<b>Author:</b> %1<br/> \
+ <b>Version:</b> %2<br/> \
+ <b>Path:</b><br/>%3<br/> \
+ <br/><b>Description:</b><br/>%4<br/> \
+ <br/><b>Dependencies: </b>%5<br/>");
+
+
+ContentSelectorModel::EsmFile::EsmFile(QString fileName, ModelItem *parent)
+ : ModelItem(parent), mFileName(fileName), mFormat(0)
+{}
+
+void ContentSelectorModel::EsmFile::setFileName(const QString &fileName)
+{
+ mFileName = fileName;
+}
+
+void ContentSelectorModel::EsmFile::setAuthor(const QString &author)
+{
+ mAuthor = author;
+}
+
+void ContentSelectorModel::EsmFile::setDate(const QDateTime &modified)
+{
+ mModified = modified;
+}
+
+void ContentSelectorModel::EsmFile::setFormat(int format)
+{
+ mFormat = format;
+}
+
+void ContentSelectorModel::EsmFile::setFilePath(const QString &path)
+{
+ mPath = path;
+}
+
+void ContentSelectorModel::EsmFile::setGameFiles(const QStringList &gamefiles)
+{
+ mGameFiles = gamefiles;
+}
+
+void ContentSelectorModel::EsmFile::setDescription(const QString &description)
+{
+ mDescription = description;
+}
+
+QByteArray ContentSelectorModel::EsmFile::encodedData() const
+{
+ QByteArray encodedData;
+ QDataStream stream(&encodedData, QIODevice::WriteOnly);
+
+ stream << mFileName << mAuthor << QString::number(mFormat)
+ << mModified.toString() << mPath << mDescription
+ << mGameFiles;
+
+ return encodedData;
+}
+
+QVariant ContentSelectorModel::EsmFile::fileProperty(const FileProperty prop) const
+{
+ switch (prop)
+ {
+ case FileProperty_FileName:
+ return mFileName;
+ break;
+
+ case FileProperty_Author:
+ return mAuthor;
+ break;
+
+ case FileProperty_Format:
+ return mFormat;
+ break;
+
+ case FileProperty_DateModified:
+ return mModified.toString(Qt::ISODate);
+ break;
+
+ case FileProperty_FilePath:
+ return mPath;
+ break;
+
+ case FileProperty_Description:
+ return mDescription;
+ break;
+
+ case FileProperty_GameFile:
+ return mGameFiles;
+ break;
+
+ default:
+ break;
+ }
+ return QVariant();
+}
+void ContentSelectorModel::EsmFile::setFileProperty (const FileProperty prop, const QString &value)
+{
+ switch (prop)
+ {
+ case FileProperty_FileName:
+ mFileName = value;
+ break;
+
+ case FileProperty_Author:
+ mAuthor = value;
+ break;
+
+ case FileProperty_Format:
+ mFormat = value.toInt();
+ break;
+
+ case FileProperty_DateModified:
+ mModified = QDateTime::fromString(value);
+ break;
+
+ case FileProperty_FilePath:
+ mPath = value;
+ break;
+
+ case FileProperty_Description:
+ mDescription = value;
+ break;
+
+ case FileProperty_GameFile:
+ mGameFiles << value;
+ break;
+
+ default:
+ break;
+ }
+}
diff --git a/components/contentselector/model/esmfile.hpp b/components/contentselector/model/esmfile.hpp
new file mode 100644
index 0000000000..ca24b52d11
--- /dev/null
+++ b/components/contentselector/model/esmfile.hpp
@@ -0,0 +1,86 @@
+#ifndef ESMFILE_HPP
+#define ESMFILE_HPP
+
+#include <QDateTime>
+#include <QStringList>
+
+#include "modelitem.hpp"
+
+class QMimeData;
+
+namespace ContentSelectorModel
+{
+ class EsmFile : public ModelItem
+ {
+ Q_OBJECT
+ Q_PROPERTY(QString filename READ fileName)
+
+ public:
+
+ enum FileProperty
+ {
+ FileProperty_FileName = 0,
+ FileProperty_Author = 1,
+ FileProperty_Format = 2,
+ FileProperty_DateModified = 3,
+ FileProperty_FilePath = 4,
+ FileProperty_Description = 5,
+ FileProperty_GameFile = 6
+ };
+
+ EsmFile(QString fileName = QString(), ModelItem *parent = 0);
+ // EsmFile(const EsmFile &);
+
+ ~EsmFile()
+ {}
+
+ void setFileProperty (const FileProperty prop, const QString &value);
+
+ void setFileName(const QString &fileName);
+ void setAuthor(const QString &author);
+ void setSize(const int size);
+ void setDate(const QDateTime &modified);
+ void setFormat(const int format);
+ void setFilePath(const QString &path);
+ void setGameFiles(const QStringList &gameFiles);
+ void setDescription(const QString &description);
+
+ inline void addGameFile (const QString &name) {mGameFiles.append(name); }
+ QVariant fileProperty (const FileProperty prop) const;
+
+ inline QString fileName() const { return mFileName; }
+ inline QString author() const { return mAuthor; }
+ inline QDateTime modified() const { return mModified; }
+ inline float format() const { return mFormat; }
+ inline QString filePath() const { return mPath; }
+ inline const QStringList &gameFiles() const { return mGameFiles; }
+ inline QString description() const { return mDescription; }
+ inline QString toolTip() const { return sToolTip.arg(mAuthor)
+ .arg(mFormat)
+ .arg(mPath)
+ .arg(mDescription)
+ .arg(mGameFiles.join(", "));
+ }
+
+ inline bool isGameFile() const { return (mGameFiles.size() == 0); }
+ QByteArray encodedData() const;
+
+ public:
+ static int sPropertyCount;
+ static QString sToolTip;
+
+ private:
+
+ QString mFileName;
+ QString mAuthor;
+ QDateTime mModified;
+ int mFormat;
+ QString mPath;
+ QStringList mGameFiles;
+ QString mDescription;
+ QString mToolTip;
+
+ };
+}
+
+#endif
diff --git a/components/contentselector/model/modelitem.cpp b/components/contentselector/model/modelitem.cpp
new file mode 100644
index 0000000000..e1d737c2d4
--- /dev/null
+++ b/components/contentselector/model/modelitem.cpp
@@ -0,0 +1,69 @@
+#include "modelitem.hpp"
+
+ContentSelectorModel::ModelItem::ModelItem(ModelItem *parent)
+ : mParentItem(parent)
+{
+}
+/*
+ContentSelectorModel::ModelItem::ModelItem(const ModelItem *parent)
+ // : mParentItem(parent)
+{
+}
+*/
+
+ContentSelectorModel::ModelItem::~ModelItem()
+{
+ qDeleteAll(mChildItems);
+}
+
+
+ContentSelectorModel::ModelItem *ContentSelectorModel::ModelItem::parent() const
+{
+ return mParentItem;
+}
+
+bool ContentSelectorModel::ModelItem::hasFormat(const QString &mimetype) const
+{
+ if (mimetype == "application/omwcontent")
+ return true;
+
+ return QMimeData::hasFormat(mimetype);
+}
+int ContentSelectorModel::ModelItem::row() const
+{
+ if (mParentItem)
+ return 1;
+ //return mParentItem->childRow(const_cast<ModelItem*>(this));
+ //return mParentItem->mChildItems.indexOf(const_cast<ModelItem*>(this));
+
+ return -1;
+}
+
+
+int ContentSelectorModel::ModelItem::childCount() const
+{
+ return mChildItems.count();
+}
+
+int ContentSelectorModel::ModelItem::childRow(ModelItem *child) const
+{
+ Q_ASSERT(child);
+
+ return mChildItems.indexOf(child);
+}
+
+ContentSelectorModel::ModelItem *ContentSelectorModel::ModelItem::child(int row)
+{
+ return mChildItems.value(row);
+}
+
+
+void ContentSelectorModel::ModelItem::appendChild(ModelItem *item)
+{
+ mChildItems.append(item);
+}
+
+void ContentSelectorModel::ModelItem::removeChild(int row)
+{
+ mChildItems.removeAt(row);
+}
diff --git a/components/contentselector/model/modelitem.hpp b/components/contentselector/model/modelitem.hpp
new file mode 100644
index 0000000000..57214b09cf
--- /dev/null
+++ b/components/contentselector/model/modelitem.hpp
@@ -0,0 +1,39 @@
+#ifndef MODELITEM_HPP
+#define MODELITEM_HPP
+
+#include <QMimeData>
+#include <QList>
+
+namespace ContentSelectorModel
+{
+ class ModelItem : public QMimeData
+ {
+ Q_OBJECT
+
+ public:
+ ModelItem(ModelItem *parent = 0);
+ //ModelItem(const ModelItem *parent = 0);
+
+ ~ModelItem();
+
+ ModelItem *parent() const;
+ int row() const;
+
+ int childCount() const;
+ int childRow(ModelItem *child) const;
+ ModelItem *child(int row);
+
+ void appendChild(ModelItem *child);
+ void removeChild(int row);
+
+ bool hasFormat(const QString &mimetype) const;
+
+ //virtual bool acceptChild(ModelItem *child);
+
+ protected:
+ ModelItem *mParentItem;
+ QList<ModelItem*> mChildItems;
+ };
+}
+
+#endif
diff --git a/components/fileorderlist/utils/naturalsort.cpp b/components/contentselector/model/naturalsort.cpp
index 50d1e77de0..50d1e77de0 100644
--- a/components/fileorderlist/utils/naturalsort.cpp
+++ b/components/contentselector/model/naturalsort.cpp
diff --git a/components/contentselector/model/naturalsort.hpp b/components/contentselector/model/naturalsort.hpp
new file mode 100644
index 0000000000..8386e4e9f0
--- /dev/null
+++ b/components/contentselector/model/naturalsort.hpp
@@ -0,0 +1,11 @@
+#ifndef NATURALSORT_H
+#define NATURALSORT_H
+
+#include <QString>
+
+ bool naturalSortLessThanCS( const QString &left, const QString &right );
+ bool naturalSortLessThanCI( const QString &left, const QString &right );
+ bool naturalSortGreaterThanCS( const QString &left, const QString &right );
+ bool naturalSortGreaterThanCI( const QString &left, const QString &right );
+
+#endif
diff --git a/components/contentselector/view/combobox.cpp b/components/contentselector/view/combobox.cpp
new file mode 100644
index 0000000000..1d773b62dd
--- /dev/null
+++ b/components/contentselector/view/combobox.cpp
@@ -0,0 +1,39 @@
+#include <QRegExpValidator>
+#include <QLineEdit>
+#include <QString>
+#include <QApplication>
+#include <QKeyEvent>
+
+#include "combobox.hpp"
+
+ContentSelectorView::ComboBox::ComboBox(QWidget *parent) :
+ QComboBox(parent)
+{
+ mValidator = new QRegExpValidator(QRegExp("^[a-zA-Z0-9_]*$"), this); // Alpha-numeric + underscore
+ setValidator(mValidator);
+ setCompleter(0);
+ setEnabled (true);
+
+ setInsertPolicy(QComboBox::NoInsert);
+}
+
+void ContentSelectorView::ComboBox::paintEvent(QPaintEvent *)
+{
+ QStylePainter painter(this);
+ painter.setPen(palette().color(QPalette::Text));
+
+ // draw the combobox frame, focusrect and selected etc.
+ QStyleOptionComboBox opt;
+ initStyleOption(&opt);
+ painter.drawComplexControl(QStyle::CC_ComboBox, opt);
+
+ // draw the icon and text
+ if (!opt.editable && currentIndex() == -1) // <<< we adjust the text displayed when nothing is selected
+ opt.currentText = mPlaceholderText;
+ painter.drawControl(QStyle::CE_ComboBoxLabel, opt);
+}
+
+void ContentSelectorView::ComboBox::setPlaceholderText(const QString &text)
+{
+ mPlaceholderText = text;
+}
diff --git a/components/contentselector/view/combobox.hpp b/components/contentselector/view/combobox.hpp
new file mode 100644
index 0000000000..e3888af2c7
--- /dev/null
+++ b/components/contentselector/view/combobox.hpp
@@ -0,0 +1,30 @@
+#ifndef COMBOBOX_HPP
+#define COMBOBOX_HPP
+
+#include <QComboBox>
+#include <QStylePainter>
+
+class QString;
+class QRegExpValidator;
+
+namespace ContentSelectorView
+{
+ class ComboBox : public QComboBox
+ {
+ Q_OBJECT
+
+ public:
+ explicit ComboBox (QWidget *parent = 0);
+
+ void setPlaceholderText(const QString &text);
+
+ private:
+ QString mPlaceholderText;
+
+ protected:
+ void paintEvent(QPaintEvent *);
+ QRegExpValidator *mValidator;
+ };
+}
+
+#endif // COMBOBOX_HPP
diff --git a/components/contentselector/view/contentselector.cpp b/components/contentselector/view/contentselector.cpp
new file mode 100644
index 0000000000..e9599de498
--- /dev/null
+++ b/components/contentselector/view/contentselector.cpp
@@ -0,0 +1,203 @@
+#include "contentselector.hpp"
+
+#include "../model/esmfile.hpp"
+
+#include <QSortFilterProxyModel>
+
+#include <QMenu>
+#include <QContextMenuEvent>
+
+#include <QGridLayout>
+#include <QMessageBox>
+#include <QModelIndex>
+#include <assert.h>
+
+ContentSelectorView::ContentSelector::ContentSelector(QWidget *parent) :
+ QObject(parent)
+{
+ ui.setupUi (parent);
+
+ buildContentModel();
+ buildGameFileView();
+ buildAddonView();
+}
+
+void ContentSelectorView::ContentSelector::buildContentModel()
+{
+ mContentModel = new ContentSelectorModel::ContentModel();
+}
+
+void ContentSelectorView::ContentSelector::buildGameFileView()
+{
+ ui.gameFileView->setVisible (true);
+
+ mGameFileProxyModel = new QSortFilterProxyModel(this);
+ mGameFileProxyModel->setFilterRegExp(QString::number((int)ContentSelectorModel::ContentType_GameFile));
+ mGameFileProxyModel->setFilterRole (Qt::UserRole);
+ mGameFileProxyModel->setSourceModel (mContentModel);
+
+ ui.gameFileView->setPlaceholderText(QString("Select a game file..."));
+ ui.gameFileView->setModel(mGameFileProxyModel);
+
+ connect (ui.gameFileView, SIGNAL (currentIndexChanged(int)),
+ this, SLOT (slotCurrentGameFileIndexChanged(int)));
+
+ ui.gameFileView->setCurrentIndex(-1);
+ ui.gameFileView->setCurrentIndex(0);
+}
+
+void ContentSelectorView::ContentSelector::buildAddonView()
+{
+ ui.addonView->setVisible (true);
+
+ mAddonProxyModel = new QSortFilterProxyModel(this);
+ mAddonProxyModel->setFilterRegExp (QString::number((int)ContentSelectorModel::ContentType_Addon));
+ mAddonProxyModel->setFilterRole (Qt::UserRole);
+ mAddonProxyModel->setDynamicSortFilter (true);
+ mAddonProxyModel->setSourceModel (mContentModel);
+
+ ui.addonView->setModel(mAddonProxyModel);
+
+ connect(ui.addonView, SIGNAL(clicked(const QModelIndex &)), this, SLOT(slotAddonTableItemClicked(const QModelIndex &)));
+}
+
+void ContentSelectorView::ContentSelector::setProfileContent(const QStringList &fileList)
+{
+ clearCheckStates();
+ bool foundGamefile = false;
+
+ foreach (const QString &filepath, fileList)
+ {
+ if (!foundGamefile)
+ {
+ const ContentSelectorModel::EsmFile *file = mContentModel->item(filepath);
+
+ foundGamefile = (file->isGameFile());
+
+ if (foundGamefile)
+ {
+ setGameFile (filepath);
+ break;
+ }
+ }
+ }
+
+/* if (!foundGameFile)
+ {
+ //throw gamefile error here.
+ }*/
+
+ setCheckStates (fileList);
+}
+
+void ContentSelectorView::ContentSelector::setGameFile(const QString &filename)
+{
+ int index = -1;
+
+ if (!filename.isEmpty())
+ {
+ const ContentSelectorModel::EsmFile *file = mContentModel->item (filename);
+ index = ui.gameFileView->findText (file->fileName());
+
+ //verify that the current index is also checked in the model
+ if (!mContentModel->setCheckState(filename, true))
+ {
+ //throw error in case file not found?
+ return;
+ }
+ }
+
+ ui.gameFileView->setCurrentIndex(index);
+}
+
+void ContentSelectorView::ContentSelector::clearCheckStates()
+{
+ mContentModel->uncheckAll();
+}
+
+void ContentSelectorView::ContentSelector::setCheckStates(const QStringList &list)
+{
+ if (list.isEmpty())
+ {
+ slotCurrentGameFileIndexChanged (ui.gameFileView->currentIndex());
+ }
+ else
+ mContentModel->setCheckStates (list, true);
+}
+
+ContentSelectorModel::ContentFileList
+ ContentSelectorView::ContentSelector::selectedFiles() const
+{
+ if (!mContentModel)
+ return ContentSelectorModel::ContentFileList();
+
+ return mContentModel->checkedItems();
+}
+
+void ContentSelectorView::ContentSelector::addFiles(const QString &path)
+{
+ mContentModel->addFiles(path);
+
+ if (ui.gameFileView->currentIndex() != -1)
+ ui.gameFileView->setCurrentIndex(-1);
+
+ mContentModel->uncheckAll();
+}
+
+QString ContentSelectorView::ContentSelector::currentFile() const
+{
+ QModelIndex currentIdx = ui.addonView->currentIndex();
+
+ if (!currentIdx.isValid())
+ return ui.gameFileView->currentText();
+
+ QModelIndex idx = mContentModel->index(mAddonProxyModel->mapToSource(currentIdx).row(), 0, QModelIndex());
+ return mContentModel->data(idx, Qt::DisplayRole).toString();
+}
+
+void ContentSelectorView::ContentSelector::slotCurrentGameFileIndexChanged(int index)
+{
+ static int oldIndex = -1;
+
+ QAbstractItemModel *const model = ui.gameFileView->model();
+ QSortFilterProxyModel *proxy = dynamic_cast<QSortFilterProxyModel *>(model);
+
+ if (proxy)
+ proxy->setDynamicSortFilter(false);
+
+ if (index != oldIndex)
+ {
+ if (oldIndex > -1)
+ model->setData(model->index(oldIndex, 0), false, Qt::UserRole + 1);
+
+ oldIndex = index;
+
+ model->setData(model->index(index, 0), true, Qt::UserRole + 1);
+ }
+
+ if (proxy)
+ proxy->setDynamicSortFilter(true);
+
+ emit signalCurrentGamefileIndexChanged (index);
+}
+
+void ContentSelectorView::ContentSelector::slotAddonTableItemClicked(const QModelIndex &index)
+{
+ QModelIndex sourceIndex = mAddonProxyModel->mapToSource (index);
+
+ if (!mContentModel->isEnabled (sourceIndex))
+ return;
+
+ Qt::CheckState checkState = Qt::Unchecked;
+
+ if (mContentModel->data(sourceIndex, Qt::CheckStateRole).toInt() == Qt::Unchecked)
+ checkState = Qt::Checked;
+
+ mContentModel->setData(sourceIndex, checkState, Qt::CheckStateRole);
+
+ if (checkState == Qt::Checked)
+ emit signalAddonFileSelected (index.row());
+ else
+ emit signalAddonFileUnselected (index.row());
+
+}
diff --git a/components/contentselector/view/contentselector.hpp b/components/contentselector/view/contentselector.hpp
new file mode 100644
index 0000000000..a25eb20ae3
--- /dev/null
+++ b/components/contentselector/view/contentselector.hpp
@@ -0,0 +1,68 @@
+#ifndef CONTENTSELECTOR_HPP
+#define CONTENTSELECTOR_HPP
+
+#include <QDialog>
+
+#include "ui_contentselector.h"
+#include "../model/contentmodel.hpp"
+
+class QSortFilterProxyModel;
+
+namespace ContentSelectorView
+{
+ class ContentSelector : public QObject
+ {
+ Q_OBJECT
+
+ QStringList mFilePaths;
+
+ protected:
+
+ ContentSelectorModel::ContentModel *mContentModel;
+ QSortFilterProxyModel *mGameFileProxyModel;
+ QSortFilterProxyModel *mAddonProxyModel;
+
+ public:
+
+ explicit ContentSelector(QWidget *parent = 0);
+
+ QString currentFile() const;
+
+ void addFiles(const QString &path);
+ void setProfileContent (const QStringList &fileList);
+
+ void clearCheckStates();
+ void setCheckStates (const QStringList &list);
+
+ ContentSelectorModel::ContentFileList selectedFiles() const;
+
+ void setGameFile (const QString &filename = QString(""));
+
+ bool isGamefileSelected() const
+ { return ui.gameFileView->currentIndex() != -1; }
+
+ QWidget *uiWidget() const
+ { return ui.contentGroupBox; }
+
+
+ private:
+
+ Ui::ContentSelector ui;
+
+ void buildContentModel();
+ void buildGameFileView();
+ void buildAddonView();
+
+ signals:
+ void signalCurrentGamefileIndexChanged (int);
+ void signalAddonFileSelected (int);
+ void signalAddonFileUnselected (int);
+
+ private slots:
+
+ void slotCurrentGameFileIndexChanged(int index);
+ void slotAddonTableItemClicked(const QModelIndex &index);
+ };
+}
+
+#endif // CONTENTSELECTOR_HPP
diff --git a/components/esm/aipackage.cpp b/components/esm/aipackage.cpp
index 1440dbd138..cf4951de7e 100644
--- a/components/esm/aipackage.cpp
+++ b/components/esm/aipackage.cpp
@@ -44,9 +44,9 @@ namespace ESM
}
}
- void AIPackageList::save(ESMWriter &esm)
+ void AIPackageList::save(ESMWriter &esm) const
{
- typedef std::vector<AIPackage>::iterator PackageIter;
+ typedef std::vector<AIPackage>::const_iterator PackageIter;
for (PackageIter it = mList.begin(); it != mList.end(); ++it) {
switch (it->mType) {
case AI_Wander:
diff --git a/components/esm/aipackage.hpp b/components/esm/aipackage.hpp
index 38499b2dd8..b06cb529a7 100644
--- a/components/esm/aipackage.hpp
+++ b/components/esm/aipackage.hpp
@@ -93,7 +93,7 @@ namespace ESM
/// it needs to use retSubName() if needed. But, hey, there
/// is only one field left (XSCL) and only two records uses AI
void load(ESMReader &esm);
- void save(ESMWriter &esm);
+ void save(ESMWriter &esm) const;
};
}
diff --git a/components/esm/cellref.cpp b/components/esm/cellref.cpp
index 95cf24d331..e91059b26f 100644
--- a/components/esm/cellref.cpp
+++ b/components/esm/cellref.cpp
@@ -3,7 +3,7 @@
#include "esmwriter.hpp"
-void ESM::CellRef::save(ESMWriter &esm)
+void ESM::CellRef::save(ESMWriter &esm) const
{
esm.writeHNT("FRMR", mRefnum);
esm.writeHNCString("NAME", mRefID);
diff --git a/components/esm/cellref.hpp b/components/esm/cellref.hpp
index 31889914ce..47cb0b99ed 100644
--- a/components/esm/cellref.hpp
+++ b/components/esm/cellref.hpp
@@ -83,7 +83,7 @@ namespace ESM
// Position and rotation of this object within the cell
Position mPos;
- void save(ESMWriter &esm);
+ void save(ESMWriter &esm) const;
void blank();
};
diff --git a/components/esm/defs.hpp b/components/esm/defs.hpp
index bd86f9ba03..dd7ebfe932 100644
--- a/components/esm/defs.hpp
+++ b/components/esm/defs.hpp
@@ -36,6 +36,7 @@ struct Position
enum RecNameInts
{
+ // format 0 / legacy
REC_ACTI = 0x49544341,
REC_ALCH = 0x48434c41,
REC_APPA = 0x41505041,
@@ -80,7 +81,10 @@ enum RecNameInts
REC_SPEL = 0x4c455053,
REC_SSCR = 0x52435353,
REC_STAT = 0x54415453,
- REC_WEAP = 0x50414557
+ REC_WEAP = 0x50414557,
+
+ // format 1
+ REC_FILT = 0x544C4946
};
}
diff --git a/components/esm/effectlist.cpp b/components/esm/effectlist.cpp
index 88f87d6e29..bc126846b1 100644
--- a/components/esm/effectlist.cpp
+++ b/components/esm/effectlist.cpp
@@ -14,9 +14,9 @@ void EffectList::load(ESMReader &esm)
}
}
-void EffectList::save(ESMWriter &esm)
+void EffectList::save(ESMWriter &esm) const
{
- for (std::vector<ENAMstruct>::iterator it = mList.begin(); it != mList.end(); ++it) {
+ for (std::vector<ENAMstruct>::const_iterator it = mList.begin(); it != mList.end(); ++it) {
esm.writeHNT<ENAMstruct>("ENAM", *it, 24);
}
}
diff --git a/components/esm/effectlist.hpp b/components/esm/effectlist.hpp
index 9f5b87aeda..04adcc5cd8 100644
--- a/components/esm/effectlist.hpp
+++ b/components/esm/effectlist.hpp
@@ -35,9 +35,9 @@ namespace ESM
std::vector<ENAMstruct> mList;
void load(ESMReader &esm);
- void save(ESMWriter &esm);
+ void save(ESMWriter &esm) const;
};
-
+
}
#endif
diff --git a/components/esm/esmreader.hpp b/components/esm/esmreader.hpp
index edc724cd2a..3bf194c4e3 100644
--- a/components/esm/esmreader.hpp
+++ b/components/esm/esmreader.hpp
@@ -34,7 +34,7 @@ public:
float getFVer() const { if(mHeader.mData.version == VER_12) return 1.2; else return 1.3; }
const std::string getAuthor() const { return mHeader.mData.author.toString(); }
const std::string getDesc() const { return mHeader.mData.desc.toString(); }
- const std::vector<Header::MasterData> &getMasters() const { return mHeader.mMaster; }
+ const std::vector<Header::MasterData> &getGameFiles() const { return mHeader.mMaster; }
int getFormat() const;
const NAME &retSubName() const { return mCtx.subName; }
uint32_t getSubSize() const { return mCtx.leftSub; }
diff --git a/components/esm/esmwriter.cpp b/components/esm/esmwriter.cpp
index 3ea6bd350a..f39aa2b898 100644
--- a/components/esm/esmwriter.cpp
+++ b/components/esm/esmwriter.cpp
@@ -2,185 +2,188 @@
#include <cassert>
#include <fstream>
-#include <iostream>
-
-bool count = true;
+#include <stdexcept>
namespace ESM
{
+ ESMWriter::ESMWriter() : mRecordCount (0), mCounting (true) {}
-int ESMWriter::getVersion()
-{
- return mHeader.mData.version;
-}
-
-void ESMWriter::setVersion(int ver)
-{
- mHeader.mData.version = ver;
-}
+ unsigned int ESMWriter::getVersion() const
+ {
+ return mHeader.mData.version;
+ }
-void ESMWriter::setAuthor(const std::string& auth)
-{
- mHeader.mData.author.assign (auth);
-}
+ void ESMWriter::setVersion(unsigned int ver)
+ {
+ mHeader.mData.version = ver;
+ }
-void ESMWriter::setDescription(const std::string& desc)
-{
- mHeader.mData.desc.assign (desc);
-}
+ void ESMWriter::setAuthor(const std::string& auth)
+ {
+ mHeader.mData.author.assign (auth);
+ }
-void ESMWriter::setRecordCount (int count)
-{
- mHeader.mData.records = count;
-}
+ void ESMWriter::setDescription(const std::string& desc)
+ {
+ mHeader.mData.desc.assign (desc);
+ }
-void ESMWriter::setFormat (int format)
-{
- mHeader.mFormat = format;
-}
+ void ESMWriter::setRecordCount (int count)
+ {
+ mHeader.mData.records = count;
+ }
-void ESMWriter::addMaster(const std::string& name, uint64_t size)
-{
- Header::MasterData d;
- d.name = name;
- d.size = size;
- mHeader.mMaster.push_back(d);
-}
+ void ESMWriter::setFormat (int format)
+ {
+ mHeader.mFormat = format;
+ }
-void ESMWriter::save(const std::string& file)
-{
- std::ofstream fs(file.c_str(), std::ios_base::out | std::ios_base::trunc);
- save(fs);
-}
+ void ESMWriter::clearMaster()
+ {
+ mHeader.mMaster.clear();
+ }
-void ESMWriter::save(std::ostream& file)
-{
- m_recordCount = 0;
- m_stream = &file;
+ void ESMWriter::addMaster(const std::string& name, uint64_t size)
+ {
+ Header::MasterData d;
+ d.name = name;
+ d.size = size;
+ mHeader.mMaster.push_back(d);
+ }
- startRecord("TES3", 0);
+ void ESMWriter::save(const std::string& file)
+ {
+ std::ofstream fs(file.c_str(), std::ios_base::out | std::ios_base::trunc);
+ save(fs);
+ }
- mHeader.save (*this);
+ void ESMWriter::save(std::ostream& file)
+ {
+ mRecordCount = 0;
+ mRecords.clear();
+ mCounting = true;
+ mStream = &file;
- endRecord("TES3");
-}
+ startRecord("TES3", 0);
-void ESMWriter::close()
-{
- m_stream->flush();
+ mHeader.save (*this);
- if (!m_records.empty())
- throw "Unclosed record remaining";
-}
-
-void ESMWriter::startRecord(const std::string& name, uint32_t flags)
-{
- m_recordCount++;
-
- writeName(name);
- RecordData rec;
- rec.name = name;
- rec.position = m_stream->tellp();
- rec.size = 0;
- writeT<int>(0); // Size goes here
- writeT<int>(0); // Unused header?
- writeT(flags);
- m_records.push_back(rec);
-
- assert(m_records.back().size == 0);
-}
+ endRecord("TES3");
+ }
-void ESMWriter::startSubRecord(const std::string& name)
-{
- writeName(name);
- RecordData rec;
- rec.name = name;
- rec.position = m_stream->tellp();
- rec.size = 0;
- writeT<int>(0); // Size goes here
- m_records.push_back(rec);
-
- assert(m_records.back().size == 0);
-}
+ void ESMWriter::close()
+ {
+ if (!mRecords.empty())
+ throw std::runtime_error ("Unclosed record remaining");
+ }
-void ESMWriter::endRecord(const std::string& name)
-{
- RecordData rec = m_records.back();
- assert(rec.name == name);
- m_records.pop_back();
+ void ESMWriter::startRecord(const std::string& name, uint32_t flags)
+ {
+ mRecordCount++;
+
+ writeName(name);
+ RecordData rec;
+ rec.name = name;
+ rec.position = mStream->tellp();
+ rec.size = 0;
+ writeT<int>(0); // Size goes here
+ writeT<int>(0); // Unused header?
+ writeT(flags);
+ mRecords.push_back(rec);
+
+ assert(mRecords.back().size == 0);
+ }
- m_stream->seekp(rec.position);
+ void ESMWriter::startSubRecord(const std::string& name)
+ {
+ writeName(name);
+ RecordData rec;
+ rec.name = name;
+ rec.position = mStream->tellp();
+ rec.size = 0;
+ writeT<int>(0); // Size goes here
+ mRecords.push_back(rec);
+
+ assert(mRecords.back().size == 0);
+ }
- count = false;
- write((char*)&rec.size, sizeof(int));
- count = true;
+ void ESMWriter::endRecord(const std::string& name)
+ {
+ RecordData rec = mRecords.back();
+ assert(rec.name == name);
+ mRecords.pop_back();
- m_stream->seekp(0, std::ios::end);
+ mStream->seekp(rec.position);
-}
+ mCounting = false;
+ write (reinterpret_cast<const char*> (&rec.size), sizeof(int));
+ mCounting = true;
-void ESMWriter::writeHNString(const std::string& name, const std::string& data)
-{
- startSubRecord(name);
- writeHString(data);
- endRecord(name);
-}
+ mStream->seekp(0, std::ios::end);
-void ESMWriter::writeHNString(const std::string& name, const std::string& data, size_t size)
-{
- assert(data.size() <= size);
- startSubRecord(name);
- writeHString(data);
+ }
- if (data.size() < size)
+ void ESMWriter::writeHNString(const std::string& name, const std::string& data)
{
- for (size_t i = data.size(); i < size; ++i)
- write("\0",1);
+ startSubRecord(name);
+ writeHString(data);
+ endRecord(name);
}
- endRecord(name);
-}
-
-void ESMWriter::writeHString(const std::string& data)
-{
- if (data.size() == 0)
- write("\0", 1);
- else
+ void ESMWriter::writeHNString(const std::string& name, const std::string& data, size_t size)
{
- // Convert to UTF8 and return
- std::string ascii = m_encoder->getLegacyEnc(data);
+ assert(data.size() <= size);
+ startSubRecord(name);
+ writeHString(data);
+
+ if (data.size() < size)
+ {
+ for (size_t i = data.size(); i < size; ++i)
+ write("\0",1);
+ }
- write(ascii.c_str(), ascii.size());
+ endRecord(name);
}
-}
-void ESMWriter::writeHCString(const std::string& data)
-{
- writeHString(data);
- if (data.size() > 0 && data[data.size()-1] != '\0')
- write("\0", 1);
-}
+ void ESMWriter::writeHString(const std::string& data)
+ {
+ if (data.size() == 0)
+ write("\0", 1);
+ else
+ {
+ // Convert to UTF8 and return
+ std::string ascii = mEncoder->getLegacyEnc(data);
+
+ write(ascii.c_str(), ascii.size());
+ }
+ }
-void ESMWriter::writeName(const std::string& name)
-{
- assert((name.size() == 4 && name[3] != '\0'));
- write(name.c_str(), name.size());
-}
+ void ESMWriter::writeHCString(const std::string& data)
+ {
+ writeHString(data);
+ if (data.size() > 0 && data[data.size()-1] != '\0')
+ write("\0", 1);
+ }
-void ESMWriter::write(const char* data, size_t size)
-{
- if (count && !m_records.empty())
+ void ESMWriter::writeName(const std::string& name)
{
- for (std::list<RecordData>::iterator it = m_records.begin(); it != m_records.end(); ++it)
- it->size += size;
+ assert((name.size() == 4 && name[3] != '\0'));
+ write(name.c_str(), name.size());
}
- m_stream->write(data, size);
-}
+ void ESMWriter::write(const char* data, size_t size)
+ {
+ if (mCounting && !mRecords.empty())
+ {
+ for (std::list<RecordData>::iterator it = mRecords.begin(); it != mRecords.end(); ++it)
+ it->size += size;
+ }
-void ESMWriter::setEncoder(ToUTF8::Utf8Encoder* encoder)
-{
- m_encoder = encoder;
-}
+ mStream->write(data, size);
+ }
+ void ESMWriter::setEncoder(ToUTF8::Utf8Encoder* encoder)
+ {
+ mEncoder = encoder;
+ }
}
diff --git a/components/esm/esmwriter.hpp b/components/esm/esmwriter.hpp
index be3ae33abe..104f97f909 100644
--- a/components/esm/esmwriter.hpp
+++ b/components/esm/esmwriter.hpp
@@ -13,92 +13,103 @@ namespace ESM {
class ESMWriter
{
- struct RecordData
- {
- std::string name;
- std::streampos position;
- size_t size;
+ struct RecordData
+ {
+ std::string name;
+ std::streampos position;
+ size_t size;
+ };
+
+ public:
+
+ ESMWriter();
+
+ unsigned int getVersion() const;
+ void setVersion(unsigned int ver = 0x3fa66666);
+ void setEncoder(ToUTF8::Utf8Encoder *encoding);
+ void setAuthor(const std::string& author);
+ void setDescription(const std::string& desc);
+ void setRecordCount (int count);
+ void setFormat (int format);
+
+ void clearMaster();
+
+ void addMaster(const std::string& name, uint64_t size);
+
+ void save(const std::string& file);
+ ///< Start saving a file by writing the TES3 header.
+
+ void save(std::ostream& file);
+ ///< Start saving a file by writing the TES3 header.
+
+ void close();
+ ///< \note Does not close the stream.
+
+ void writeHNString(const std::string& name, const std::string& data);
+ void writeHNString(const std::string& name, const std::string& data, size_t size);
+ void writeHNCString(const std::string& name, const std::string& data)
+ {
+ startSubRecord(name);
+ writeHCString(data);
+ endRecord(name);
+ }
+ void writeHNOString(const std::string& name, const std::string& data)
+ {
+ if (!data.empty())
+ writeHNString(name, data);
+ }
+ void writeHNOCString(const std::string& name, const std::string& data)
+ {
+ if (!data.empty())
+ writeHNCString(name, data);
+ }
+
+ template<typename T>
+ void writeHNT(const std::string& name, const T& data)
+ {
+ startSubRecord(name);
+ writeT(data);
+ endRecord(name);
+ }
+
+ template<typename T>
+ void writeHNT(const std::string& name, const T& data, int size)
+ {
+ startSubRecord(name);
+ writeT(data, size);
+ endRecord(name);
+ }
+
+ template<typename T>
+ void writeT(const T& data)
+ {
+ write((char*)&data, sizeof(T));
+ }
+
+ template<typename T>
+ void writeT(const T& data, size_t size)
+ {
+ write((char*)&data, size);
+ }
+
+ void startRecord(const std::string& name, uint32_t flags = 0);
+ void startSubRecord(const std::string& name);
+ void endRecord(const std::string& name);
+ void writeHString(const std::string& data);
+ void writeHCString(const std::string& data);
+ void writeName(const std::string& data);
+ void write(const char* data, size_t size);
+
+ private:
+ std::list<RecordData> mRecords;
+ std::ostream* mStream;
+ std::streampos mHeaderPos;
+ ToUTF8::Utf8Encoder* mEncoder;
+ int mRecordCount;
+ bool mCounting;
+
+ Header mHeader;
};
-
-public:
- int getVersion();
- void setVersion(int ver);
- void setEncoder(ToUTF8::Utf8Encoder *encoding); // Write strings as UTF-8?
- void setAuthor(const std::string& author);
- void setDescription(const std::string& desc);
- void setRecordCount (int count);
- void setFormat (int format);
-
- void addMaster(const std::string& name, uint64_t size);
-
- void save(const std::string& file);
- void save(std::ostream& file);
- void close();
-
- void writeHNString(const std::string& name, const std::string& data);
- void writeHNString(const std::string& name, const std::string& data, size_t size);
- void writeHNCString(const std::string& name, const std::string& data)
- {
- startSubRecord(name);
- writeHCString(data);
- endRecord(name);
- }
- void writeHNOString(const std::string& name, const std::string& data)
- {
- if (!data.empty())
- writeHNString(name, data);
- }
- void writeHNOCString(const std::string& name, const std::string& data)
- {
- if (!data.empty())
- writeHNCString(name, data);
- }
-
- template<typename T>
- void writeHNT(const std::string& name, const T& data)
- {
- startSubRecord(name);
- writeT(data);
- endRecord(name);
- }
-
- template<typename T>
- void writeHNT(const std::string& name, const T& data, int size)
- {
- startSubRecord(name);
- writeT(data, size);
- endRecord(name);
- }
-
- template<typename T>
- void writeT(const T& data)
- {
- write((char*)&data, sizeof(T));
- }
-
- template<typename T>
- void writeT(const T& data, size_t size)
- {
- write((char*)&data, size);
- }
-
- void startRecord(const std::string& name, uint32_t flags);
- void startSubRecord(const std::string& name);
- void endRecord(const std::string& name);
- void writeHString(const std::string& data);
- void writeHCString(const std::string& data);
- void writeName(const std::string& data);
- void write(const char* data, size_t size);
-
-private:
- std::list<RecordData> m_records;
- std::ostream* m_stream;
- std::streampos m_headerPos;
- ToUTF8::Utf8Encoder* m_encoder;
- int m_recordCount;
-
- Header mHeader;
-};
-
}
+
#endif
diff --git a/components/esm/filter.cpp b/components/esm/filter.cpp
index 7d4851a5f6..a80427bbed 100644
--- a/components/esm/filter.cpp
+++ b/components/esm/filter.cpp
@@ -3,6 +3,9 @@
#include "esmreader.hpp"
#include "esmwriter.hpp"
+#include "defs.hpp"
+
+unsigned int ESM::Filter::sRecordId = REC_FILT;
void ESM::Filter::load (ESMReader& esm)
{
@@ -10,7 +13,7 @@ void ESM::Filter::load (ESMReader& esm)
mDescription = esm.getHNString ("DESC");
}
-void ESM::Filter::save (ESMWriter& esm)
+void ESM::Filter::save (ESMWriter& esm) const
{
esm.writeHNCString ("FILT", mFilter);
esm.writeHNCString ("DESC", mDescription);
diff --git a/components/esm/filter.hpp b/components/esm/filter.hpp
index 0fd564361e..bc3dd7bdcb 100644
--- a/components/esm/filter.hpp
+++ b/components/esm/filter.hpp
@@ -10,6 +10,8 @@ namespace ESM
struct Filter
{
+ static unsigned int sRecordId;
+
std::string mId;
std::string mDescription;
@@ -17,7 +19,7 @@ namespace ESM
std::string mFilter;
void load (ESMReader& esm);
- void save (ESMWriter& esm);
+ void save (ESMWriter& esm) const;
void blank();
///< Set record to default state (does not touch the ID).
diff --git a/components/esm/loadacti.cpp b/components/esm/loadacti.cpp
index fd022af7e6..6ba0df0b36 100644
--- a/components/esm/loadacti.cpp
+++ b/components/esm/loadacti.cpp
@@ -2,16 +2,19 @@
#include "esmreader.hpp"
#include "esmwriter.hpp"
+#include "defs.hpp"
namespace ESM
{
+ unsigned int Activator::sRecordId = REC_ACTI;
+
void Activator::load(ESMReader &esm)
{
mModel = esm.getHNString("MODL");
mName = esm.getHNString("FNAM");
mScript = esm.getHNOString("SCRI");
}
-void Activator::save(ESMWriter &esm)
+void Activator::save(ESMWriter &esm) const
{
esm.writeHNCString("MODL", mModel);
esm.writeHNCString("FNAM", mName);
diff --git a/components/esm/loadacti.hpp b/components/esm/loadacti.hpp
index a62990590d..88f27de27e 100644
--- a/components/esm/loadacti.hpp
+++ b/components/esm/loadacti.hpp
@@ -11,10 +11,12 @@ class ESMWriter;
struct Activator
{
+ static unsigned int sRecordId;
+
std::string mId, mName, mScript, mModel;
void load(ESMReader &esm);
- void save(ESMWriter &esm);
+ void save(ESMWriter &esm) const;
void blank();
///< Set record to default state (does not touch the ID).
diff --git a/components/esm/loadalch.cpp b/components/esm/loadalch.cpp
index dbb69c066f..f6bfc6a11d 100644
--- a/components/esm/loadalch.cpp
+++ b/components/esm/loadalch.cpp
@@ -2,9 +2,12 @@
#include "esmreader.hpp"
#include "esmwriter.hpp"
+#include "defs.hpp"
namespace ESM
{
+ unsigned int Potion::sRecordId = REC_ALCH;
+
void Potion::load(ESMReader &esm)
{
mModel = esm.getHNString("MODL");
@@ -14,7 +17,7 @@ void Potion::load(ESMReader &esm)
esm.getHNT(mData, "ALDT", 12);
mEffects.load(esm);
}
-void Potion::save(ESMWriter &esm)
+void Potion::save(ESMWriter &esm) const
{
esm.writeHNCString("MODL", mModel);
esm.writeHNOCString("TEXT", mIcon);
diff --git a/components/esm/loadalch.hpp b/components/esm/loadalch.hpp
index 3ede853424..141765aa82 100644
--- a/components/esm/loadalch.hpp
+++ b/components/esm/loadalch.hpp
@@ -17,6 +17,8 @@ class ESMWriter;
struct Potion
{
+ static unsigned int sRecordId;
+
struct ALDTstruct
{
float mWeight;
@@ -29,7 +31,7 @@ struct Potion
EffectList mEffects;
void load(ESMReader &esm);
- void save(ESMWriter &esm);
+ void save(ESMWriter &esm) const;
void blank();
///< Set record to default state (does not touch the ID).
diff --git a/components/esm/loadappa.cpp b/components/esm/loadappa.cpp
index 4b8d2b763c..29ea78acc0 100644
--- a/components/esm/loadappa.cpp
+++ b/components/esm/loadappa.cpp
@@ -2,9 +2,12 @@
#include "esmreader.hpp"
#include "esmwriter.hpp"
+#include "defs.hpp"
namespace ESM
{
+ unsigned int Apparatus::sRecordId = REC_APPA;
+
void Apparatus::load(ESMReader &esm)
{
// we will not treat duplicated subrecords as errors here
@@ -28,7 +31,7 @@ void Apparatus::load(ESMReader &esm)
}
}
-void Apparatus::save(ESMWriter &esm)
+void Apparatus::save(ESMWriter &esm) const
{
esm.writeHNCString("MODL", mModel);
esm.writeHNCString("FNAM", mName);
diff --git a/components/esm/loadappa.hpp b/components/esm/loadappa.hpp
index ed9d335be6..adc8e071f1 100644
--- a/components/esm/loadappa.hpp
+++ b/components/esm/loadappa.hpp
@@ -15,6 +15,8 @@ class ESMWriter;
struct Apparatus
{
+ static unsigned int sRecordId;
+
enum AppaType
{
MortarPestle = 0,
@@ -35,7 +37,7 @@ struct Apparatus
std::string mId, mModel, mIcon, mScript, mName;
void load(ESMReader &esm);
- void save(ESMWriter &esm);
+ void save(ESMWriter &esm) const;
void blank();
///< Set record to default state (does not touch the ID).
diff --git a/components/esm/loadarmo.cpp b/components/esm/loadarmo.cpp
index e64c8705d7..ec8ff4f20c 100644
--- a/components/esm/loadarmo.cpp
+++ b/components/esm/loadarmo.cpp
@@ -2,6 +2,7 @@
#include "esmreader.hpp"
#include "esmwriter.hpp"
+#include "defs.hpp"
namespace ESM
{
@@ -18,9 +19,9 @@ void PartReferenceList::load(ESMReader &esm)
}
}
-void PartReferenceList::save(ESMWriter &esm)
+void PartReferenceList::save(ESMWriter &esm) const
{
- for (std::vector<PartReference>::iterator it = mParts.begin(); it != mParts.end(); ++it)
+ for (std::vector<PartReference>::const_iterator it = mParts.begin(); it != mParts.end(); ++it)
{
esm.writeHNT("INDX", it->mPart);
esm.writeHNOString("BNAM", it->mMale);
@@ -28,6 +29,8 @@ void PartReferenceList::save(ESMWriter &esm)
}
}
+unsigned int Armor::sRecordId = REC_ARMO;
+
void Armor::load(ESMReader &esm)
{
mModel = esm.getHNString("MODL");
@@ -39,7 +42,7 @@ void Armor::load(ESMReader &esm)
mEnchant = esm.getHNOString("ENAM");
}
-void Armor::save(ESMWriter &esm)
+void Armor::save(ESMWriter &esm) const
{
esm.writeHNCString("MODL", mModel);
esm.writeHNCString("FNAM", mName);
diff --git a/components/esm/loadarmo.hpp b/components/esm/loadarmo.hpp
index eaef42be83..991f4e1855 100644
--- a/components/esm/loadarmo.hpp
+++ b/components/esm/loadarmo.hpp
@@ -56,11 +56,13 @@ struct PartReferenceList
std::vector<PartReference> mParts;
void load(ESMReader &esm);
- void save(ESMWriter &esm);
+ void save(ESMWriter &esm) const;
};
struct Armor
{
+ static unsigned int sRecordId;
+
enum Type
{
Helmet = 0,
@@ -89,7 +91,7 @@ struct Armor
std::string mId, mName, mModel, mIcon, mScript, mEnchant;
void load(ESMReader &esm);
- void save(ESMWriter &esm);
+ void save(ESMWriter &esm) const;
void blank();
///< Set record to default state (does not touch the ID).
diff --git a/components/esm/loadbody.cpp b/components/esm/loadbody.cpp
index e95a8a8603..4015e6c91a 100644
--- a/components/esm/loadbody.cpp
+++ b/components/esm/loadbody.cpp
@@ -2,9 +2,12 @@
#include "esmreader.hpp"
#include "esmwriter.hpp"
+#include "defs.hpp"
namespace ESM
{
+ unsigned int BodyPart::sRecordId = REC_BODY;
+
void BodyPart::load(ESMReader &esm)
{
@@ -12,7 +15,7 @@ void BodyPart::load(ESMReader &esm)
mRace = esm.getHNString("FNAM");
esm.getHNT(mData, "BYDT", 4);
}
-void BodyPart::save(ESMWriter &esm)
+void BodyPart::save(ESMWriter &esm) const
{
esm.writeHNCString("MODL", mModel);
esm.writeHNCString("FNAM", mRace);
diff --git a/components/esm/loadbody.hpp b/components/esm/loadbody.hpp
index 3ad9b1b958..9623caa31e 100644
--- a/components/esm/loadbody.hpp
+++ b/components/esm/loadbody.hpp
@@ -11,6 +11,8 @@ class ESMWriter;
struct BodyPart
{
+ static unsigned int sRecordId;
+
enum MeshPart
{
MP_Head = 0,
@@ -57,7 +59,7 @@ struct BodyPart
std::string mId, mModel, mRace;
void load(ESMReader &esm);
- void save(ESMWriter &esm);
+ void save(ESMWriter &esm) const;
};
}
#endif
diff --git a/components/esm/loadbook.cpp b/components/esm/loadbook.cpp
index 3a70ac7869..c8b7e94789 100644
--- a/components/esm/loadbook.cpp
+++ b/components/esm/loadbook.cpp
@@ -2,9 +2,11 @@
#include "esmreader.hpp"
#include "esmwriter.hpp"
+#include "defs.hpp"
namespace ESM
{
+ unsigned int Book::sRecordId = REC_BOOK;
void Book::load(ESMReader &esm)
{
@@ -16,7 +18,7 @@ void Book::load(ESMReader &esm)
mText = esm.getHNOString("TEXT");
mEnchant = esm.getHNOString("ENAM");
}
-void Book::save(ESMWriter &esm)
+void Book::save(ESMWriter &esm) const
{
esm.writeHNCString("MODL", mModel);
esm.writeHNOCString("FNAM", mName);
diff --git a/components/esm/loadbook.hpp b/components/esm/loadbook.hpp
index 68042e246e..f96fbd709b 100644
--- a/components/esm/loadbook.hpp
+++ b/components/esm/loadbook.hpp
@@ -14,6 +14,8 @@ class ESMWriter;
struct Book
{
+ static unsigned int sRecordId;
+
struct BKDTstruct
{
float mWeight;
@@ -25,7 +27,7 @@ struct Book
std::string mId;
void load(ESMReader &esm);
- void save(ESMWriter &esm);
+ void save(ESMWriter &esm) const;
void blank();
///< Set record to default state (does not touch the ID).
diff --git a/components/esm/loadbsgn.cpp b/components/esm/loadbsgn.cpp
index cb500f6748..55e1e7f65a 100644
--- a/components/esm/loadbsgn.cpp
+++ b/components/esm/loadbsgn.cpp
@@ -2,9 +2,11 @@
#include "esmreader.hpp"
#include "esmwriter.hpp"
+#include "defs.hpp"
namespace ESM
{
+ unsigned int BirthSign::sRecordId = REC_BSGN;
void BirthSign::load(ESMReader &esm)
{
@@ -15,7 +17,7 @@ void BirthSign::load(ESMReader &esm)
mPowers.load(esm);
}
-void BirthSign::save(ESMWriter &esm)
+void BirthSign::save(ESMWriter &esm) const
{
esm.writeHNCString("FNAM", mName);
esm.writeHNOCString("TNAM", mTexture);
diff --git a/components/esm/loadbsgn.hpp b/components/esm/loadbsgn.hpp
index 434ddf68ea..9f9435c8f1 100644
--- a/components/esm/loadbsgn.hpp
+++ b/components/esm/loadbsgn.hpp
@@ -13,13 +13,15 @@ class ESMWriter;
struct BirthSign
{
+ static unsigned int sRecordId;
+
std::string mId, mName, mDescription, mTexture;
// List of powers and abilities that come with this birth sign.
SpellList mPowers;
void load(ESMReader &esm);
- void save(ESMWriter &esm);
+ void save(ESMWriter &esm) const;
void blank();
///< Set record to default state (does not touch the ID/index).
diff --git a/components/esm/loadcell.cpp b/components/esm/loadcell.cpp
index d8d0c12912..c22c1b22b6 100644
--- a/components/esm/loadcell.cpp
+++ b/components/esm/loadcell.cpp
@@ -7,9 +7,11 @@
#include "esmreader.hpp"
#include "esmwriter.hpp"
+#include "defs.hpp"
namespace ESM
{
+ unsigned int Cell::sRecordId = REC_CELL;
/// Some overloaded compare operators.
bool operator==(const MovedCellRef& ref, int pRefnum)
@@ -89,7 +91,7 @@ void Cell::postLoad(ESMReader &esm)
esm.skipRecord();
}
-void Cell::save(ESMWriter &esm)
+void Cell::save(ESMWriter &esm) const
{
esm.writeHNT("DATA", mData, 12);
if (mData.mFlags & Interior)
@@ -172,7 +174,7 @@ bool Cell::getNextRef(ESMReader &esm, CellRef &ref)
// If the most significant 8 bits are used, then this reference already exists.
// In this case, do not spawn a new reference, but overwrite the old one.
ref.mRefnum &= 0x00ffffff; // delete old plugin ID
- const std::vector<Header::MasterData> &masters = esm.getMasters();
+ const std::vector<Header::MasterData> &masters = esm.getGameFiles();
global = masters[local-1].index + 1;
ref.mRefnum |= global << 24; // insert global plugin ID
}
@@ -276,7 +278,7 @@ bool Cell::getNextMVRF(ESMReader &esm, MovedCellRef &mref)
int local = (mref.mRefnum & 0xff000000) >> 24;
size_t global = esm.getIndex() + 1;
mref.mRefnum &= 0x00ffffff; // delete old plugin ID
- const std::vector<Header::MasterData> &masters = esm.getMasters();
+ const std::vector<Header::MasterData> &masters = esm.getGameFiles();
global = masters[local-1].index + 1;
mref.mRefnum |= global << 24; // insert global plugin ID
diff --git a/components/esm/loadcell.hpp b/components/esm/loadcell.hpp
index 51288b2919..61d586b9d8 100644
--- a/components/esm/loadcell.hpp
+++ b/components/esm/loadcell.hpp
@@ -16,7 +16,6 @@ namespace MWWorld
namespace ESM
{
-
class ESMReader;
class ESMWriter;
@@ -55,6 +54,8 @@ typedef std::list<CellRef> CellRefTracker;
*/
struct Cell
{
+ static unsigned int sRecordId;
+
enum Flags
{
Interior = 0x01, // Interior cell
@@ -102,7 +103,7 @@ struct Cell
// This method is left in for compatibility with esmtool. Parsing moved references currently requires
// passing ESMStore, bit it does not know about this parameter, so we do it this way.
void load(ESMReader &esm, bool saveContext = true);
- void save(ESMWriter &esm);
+ void save(ESMWriter &esm) const;
bool isExterior() const
{
diff --git a/components/esm/loadclas.cpp b/components/esm/loadclas.cpp
index bdc4614625..33489eec46 100644
--- a/components/esm/loadclas.cpp
+++ b/components/esm/loadclas.cpp
@@ -4,9 +4,11 @@
#include "esmreader.hpp"
#include "esmwriter.hpp"
+#include "defs.hpp"
namespace ESM
{
+ unsigned int Class::sRecordId = REC_CLAS;
const Class::Specialization Class::sSpecializationIds[3] = {
Class::Combat,
@@ -47,7 +49,7 @@ void Class::load(ESMReader &esm)
mDescription = esm.getHNOString("DESC");
}
-void Class::save(ESMWriter &esm)
+void Class::save(ESMWriter &esm) const
{
esm.writeHNCString("FNAM", mName);
esm.writeHNT("CLDT", mData, 60);
diff --git a/components/esm/loadclas.hpp b/components/esm/loadclas.hpp
index 4f85e6ee8b..3e489bb58a 100644
--- a/components/esm/loadclas.hpp
+++ b/components/esm/loadclas.hpp
@@ -17,6 +17,8 @@ class ESMWriter;
// class
struct Class
{
+ static unsigned int sRecordId;
+
enum AutoCalc
{
Weapon = 0x00001,
@@ -70,7 +72,7 @@ struct Class
CLDTstruct mData;
void load(ESMReader &esm);
- void save(ESMWriter &esm);
+ void save(ESMWriter &esm) const;
void blank();
///< Set record to default state (does not touch the ID/index).
diff --git a/components/esm/loadclot.cpp b/components/esm/loadclot.cpp
index 10b00970fb..d64564d77f 100644
--- a/components/esm/loadclot.cpp
+++ b/components/esm/loadclot.cpp
@@ -2,9 +2,11 @@
#include "esmreader.hpp"
#include "esmwriter.hpp"
+#include "defs.hpp"
namespace ESM
{
+ unsigned int Clothing::sRecordId = REC_CLOT;
void Clothing::load(ESMReader &esm)
{
@@ -20,7 +22,7 @@ void Clothing::load(ESMReader &esm)
mEnchant = esm.getHNOString("ENAM");
}
-void Clothing::save(ESMWriter &esm)
+void Clothing::save(ESMWriter &esm) const
{
esm.writeHNCString("MODL", mModel);
esm.writeHNOCString("FNAM", mName);
diff --git a/components/esm/loadclot.hpp b/components/esm/loadclot.hpp
index 816d03cb23..50896622aa 100644
--- a/components/esm/loadclot.hpp
+++ b/components/esm/loadclot.hpp
@@ -17,6 +17,8 @@ class ESMWriter;
struct Clothing
{
+ static unsigned int sRecordId;
+
enum Type
{
Pants = 0,
@@ -45,7 +47,7 @@ struct Clothing
std::string mId, mName, mModel, mIcon, mEnchant, mScript;
void load(ESMReader &esm);
- void save(ESMWriter &esm);
+ void save(ESMWriter &esm) const;
void blank();
///< Set record to default state (does not touch the ID).
diff --git a/components/esm/loadcont.cpp b/components/esm/loadcont.cpp
index 853c8bd500..7bdf9f05b1 100644
--- a/components/esm/loadcont.cpp
+++ b/components/esm/loadcont.cpp
@@ -2,6 +2,7 @@
#include "esmreader.hpp"
#include "esmwriter.hpp"
+#include "defs.hpp"
namespace ESM
{
@@ -16,14 +17,16 @@ void InventoryList::load(ESMReader &esm)
}
}
-void InventoryList::save(ESMWriter &esm)
+void InventoryList::save(ESMWriter &esm) const
{
- for (std::vector<ContItem>::iterator it = mList.begin(); it != mList.end(); ++it)
+ for (std::vector<ContItem>::const_iterator it = mList.begin(); it != mList.end(); ++it)
{
esm.writeHNT("NPCO", *it, 36);
}
}
+ unsigned int Container::sRecordId = REC_CONT;
+
void Container::load(ESMReader &esm)
{
mModel = esm.getHNString("MODL");
@@ -41,7 +44,7 @@ void Container::load(ESMReader &esm)
mInventory.load(esm);
}
-void Container::save(ESMWriter &esm)
+void Container::save(ESMWriter &esm) const
{
esm.writeHNCString("MODL", mModel);
esm.writeHNOCString("FNAM", mName);
diff --git a/components/esm/loadcont.hpp b/components/esm/loadcont.hpp
index b2bbab73d0..2808b67b56 100644
--- a/components/esm/loadcont.hpp
+++ b/components/esm/loadcont.hpp
@@ -27,11 +27,13 @@ struct InventoryList
std::vector<ContItem> mList;
void load(ESMReader &esm);
- void save(ESMWriter &esm);
+ void save(ESMWriter &esm) const;
};
struct Container
{
+ static unsigned int sRecordId;
+
enum Flags
{
Organic = 1, // Objects cannot be placed in this container
@@ -46,7 +48,7 @@ struct Container
InventoryList mInventory;
void load(ESMReader &esm);
- void save(ESMWriter &esm);
+ void save(ESMWriter &esm) const;
void blank();
///< Set record to default state (does not touch the ID).
diff --git a/components/esm/loadcrea.cpp b/components/esm/loadcrea.cpp
index 86d05b8a57..650de08011 100644
--- a/components/esm/loadcrea.cpp
+++ b/components/esm/loadcrea.cpp
@@ -2,9 +2,12 @@
#include "esmreader.hpp"
#include "esmwriter.hpp"
+#include "defs.hpp"
namespace ESM {
+ unsigned int Creature::sRecordId = REC_CREA;
+
void Creature::load(ESMReader &esm)
{
mPersistent = esm.getRecordFlags() & 0x0400;
@@ -35,7 +38,7 @@ void Creature::load(ESMReader &esm)
esm.skipRecord();
}
-void Creature::save(ESMWriter &esm)
+void Creature::save(ESMWriter &esm) const
{
esm.writeHNCString("MODL", mModel);
esm.writeHNOCString("CNAM", mOriginal);
diff --git a/components/esm/loadcrea.hpp b/components/esm/loadcrea.hpp
index 279e2ea3f4..99c4f52257 100644
--- a/components/esm/loadcrea.hpp
+++ b/components/esm/loadcrea.hpp
@@ -20,6 +20,8 @@ class ESMWriter;
struct Creature
{
+ static unsigned int sRecordId;
+
// Default is 0x48?
enum Flags
{
@@ -86,7 +88,7 @@ struct Creature
AIPackageList mAiPackage;
void load(ESMReader &esm);
- void save(ESMWriter &esm);
+ void save(ESMWriter &esm) const;
void blank();
///< Set record to default state (does not touch the ID).
diff --git a/components/esm/loadcrec.hpp b/components/esm/loadcrec.hpp
index 6904df15a4..280739acad 100644
--- a/components/esm/loadcrec.hpp
+++ b/components/esm/loadcrec.hpp
@@ -17,6 +17,8 @@ class ESMWriter;
/// Changes a creature
struct LoadCREC
{
+ static unsigned int sRecordId;
+
std::string mId;
void load(ESMReader &esm)
@@ -24,7 +26,7 @@ struct LoadCREC
esm.skipRecord();
}
- void save(ESMWriter &esm)
+ void save(ESMWriter &esm) const
{
}
};
@@ -39,7 +41,7 @@ struct LoadCNTC
esm.skipRecord();
}
- void save(ESMWriter &esm)
+ void save(ESMWriter &esm) const
{
}
};
diff --git a/components/esm/loaddial.cpp b/components/esm/loaddial.cpp
index fb50d5e9f5..fb43ee8586 100644
--- a/components/esm/loaddial.cpp
+++ b/components/esm/loaddial.cpp
@@ -2,9 +2,11 @@
#include "esmreader.hpp"
#include "esmwriter.hpp"
+#include "defs.hpp"
namespace ESM
{
+ unsigned int Dialogue::sRecordId = REC_DIAL;
void Dialogue::load(ESMReader &esm)
{
@@ -25,7 +27,7 @@ void Dialogue::load(ESMReader &esm)
esm.fail("Unknown sub record size");
}
-void Dialogue::save(ESMWriter &esm)
+void Dialogue::save(ESMWriter &esm) const
{
if (mType != Deleted)
esm.writeHNT("DATA", mType);
@@ -36,4 +38,9 @@ void Dialogue::save(ESMWriter &esm)
}
}
+ void Dialogue::blank()
+ {
+ mInfo.clear();
+ }
+
}
diff --git a/components/esm/loaddial.hpp b/components/esm/loaddial.hpp
index 61f3f763de..63d78833e1 100644
--- a/components/esm/loaddial.hpp
+++ b/components/esm/loaddial.hpp
@@ -19,6 +19,8 @@ class ESMWriter;
struct Dialogue
{
+ static unsigned int sRecordId;
+
enum Type
{
Topic = 0,
@@ -34,7 +36,10 @@ struct Dialogue
std::vector<DialInfo> mInfo;
void load(ESMReader &esm);
- void save(ESMWriter &esm);
+ void save(ESMWriter &esm) const;
+
+ void blank();
+ ///< Set record to default state (does not touch the ID and does not change the type).
};
}
#endif
diff --git a/components/esm/loaddoor.cpp b/components/esm/loaddoor.cpp
index a4c7b7d58b..c56b063379 100644
--- a/components/esm/loaddoor.cpp
+++ b/components/esm/loaddoor.cpp
@@ -2,9 +2,11 @@
#include "esmreader.hpp"
#include "esmwriter.hpp"
+#include "defs.hpp"
namespace ESM
{
+ unsigned int Door::sRecordId = REC_DOOR;
void Door::load(ESMReader &esm)
{
@@ -15,7 +17,7 @@ void Door::load(ESMReader &esm)
mCloseSound = esm.getHNOString("ANAM");
}
-void Door::save(ESMWriter &esm)
+void Door::save(ESMWriter &esm) const
{
esm.writeHNCString("MODL", mModel);
esm.writeHNOCString("FNAM", mName);
diff --git a/components/esm/loaddoor.hpp b/components/esm/loaddoor.hpp
index 77ffc64899..ee2b7f7ac5 100644
--- a/components/esm/loaddoor.hpp
+++ b/components/esm/loaddoor.hpp
@@ -11,10 +11,12 @@ class ESMWriter;
struct Door
{
+ static unsigned int sRecordId;
+
std::string mId, mName, mModel, mScript, mOpenSound, mCloseSound;
void load(ESMReader &esm);
- void save(ESMWriter &esm);
+ void save(ESMWriter &esm) const;
void blank();
///< Set record to default state (does not touch the ID).
diff --git a/components/esm/loadench.cpp b/components/esm/loadench.cpp
index c4e278368e..a1e885f23b 100644
--- a/components/esm/loadench.cpp
+++ b/components/esm/loadench.cpp
@@ -2,9 +2,11 @@
#include "esmreader.hpp"
#include "esmwriter.hpp"
+#include "defs.hpp"
namespace ESM
{
+ unsigned int Enchantment::sRecordId = REC_ENCH;
void Enchantment::load(ESMReader &esm)
{
@@ -12,7 +14,7 @@ void Enchantment::load(ESMReader &esm)
mEffects.load(esm);
}
-void Enchantment::save(ESMWriter &esm)
+void Enchantment::save(ESMWriter &esm) const
{
esm.writeHNT("ENDT", mData, 16);
mEffects.save(esm);
diff --git a/components/esm/loadench.hpp b/components/esm/loadench.hpp
index 999f93ad97..f6ba8c6ab3 100644
--- a/components/esm/loadench.hpp
+++ b/components/esm/loadench.hpp
@@ -17,6 +17,8 @@ class ESMWriter;
struct Enchantment
{
+ static unsigned int sRecordId;
+
enum Type
{
CastOnce = 0,
@@ -39,7 +41,7 @@ struct Enchantment
EffectList mEffects;
void load(ESMReader &esm);
- void save(ESMWriter &esm);
+ void save(ESMWriter &esm) const;
};
}
#endif
diff --git a/components/esm/loadfact.cpp b/components/esm/loadfact.cpp
index e2712d462d..61fa902639 100644
--- a/components/esm/loadfact.cpp
+++ b/components/esm/loadfact.cpp
@@ -4,9 +4,12 @@
#include "esmreader.hpp"
#include "esmwriter.hpp"
+#include "defs.hpp"
namespace ESM
{
+ unsigned int Faction::sRecordId = REC_FACT;
+
int& Faction::FADTstruct::getSkill (int index, bool ignored)
{
if (index<0 || index>=6)
@@ -47,7 +50,7 @@ void Faction::load(ESMReader &esm)
mReactions.push_back(r);
}
}
-void Faction::save(ESMWriter &esm)
+void Faction::save(ESMWriter &esm) const
{
esm.writeHNCString("FNAM", mName);
@@ -61,7 +64,7 @@ void Faction::save(ESMWriter &esm)
esm.writeHNT("FADT", mData, 240);
- for (std::vector<Reaction>::iterator it = mReactions.begin(); it != mReactions.end(); ++it)
+ for (std::vector<Reaction>::const_iterator it = mReactions.begin(); it != mReactions.end(); ++it)
{
esm.writeHNString("ANAM", it->mFaction);
esm.writeHNT("INTV", it->mReaction);
diff --git a/components/esm/loadfact.hpp b/components/esm/loadfact.hpp
index 891b996473..9c257e068e 100644
--- a/components/esm/loadfact.hpp
+++ b/components/esm/loadfact.hpp
@@ -29,6 +29,8 @@ struct RankData
struct Faction
{
+ static unsigned int sRecordId;
+
std::string mId, mName;
struct FADTstruct
@@ -63,7 +65,7 @@ struct Faction
std::string mRanks[10];
void load(ESMReader &esm);
- void save(ESMWriter &esm);
+ void save(ESMWriter &esm) const;
void blank();
///< Set record to default state (does not touch the ID/index).
diff --git a/components/esm/loadglob.cpp b/components/esm/loadglob.cpp
index ccb519acd4..a78ed1a1be 100644
--- a/components/esm/loadglob.cpp
+++ b/components/esm/loadglob.cpp
@@ -1,13 +1,17 @@
#include "loadglob.hpp"
+#include "defs.hpp"
+
namespace ESM
{
+ unsigned int Global::sRecordId = REC_GLOB;
+
void Global::load (ESMReader &esm)
{
mValue.read (esm, ESM::Variant::Format_Global);
}
- void Global::save (ESMWriter &esm)
+ void Global::save (ESMWriter &esm) const
{
mValue.write (esm, ESM::Variant::Format_Global);
}
diff --git a/components/esm/loadglob.hpp b/components/esm/loadglob.hpp
index 72e16c0ce5..51b2e2dc98 100644
--- a/components/esm/loadglob.hpp
+++ b/components/esm/loadglob.hpp
@@ -17,11 +17,13 @@ class ESMWriter;
struct Global
{
+ static unsigned int sRecordId;
+
std::string mId;
Variant mValue;
void load(ESMReader &esm);
- void save(ESMWriter &esm);
+ void save(ESMWriter &esm) const;
void blank();
///< Set record to default state (does not touch the ID).
diff --git a/components/esm/loadgmst.cpp b/components/esm/loadgmst.cpp
index fe1cc1b047..21d66339a9 100644
--- a/components/esm/loadgmst.cpp
+++ b/components/esm/loadgmst.cpp
@@ -1,13 +1,17 @@
#include "loadgmst.hpp"
+#include "defs.hpp"
+
namespace ESM
{
+ unsigned int GameSetting::sRecordId = REC_GMST;
+
void GameSetting::load (ESMReader &esm)
{
mValue.read (esm, ESM::Variant::Format_Gmst);
}
- void GameSetting::save (ESMWriter &esm)
+ void GameSetting::save (ESMWriter &esm) const
{
mValue.write (esm, ESM::Variant::Format_Gmst);
}
diff --git a/components/esm/loadgmst.hpp b/components/esm/loadgmst.hpp
index a6e0c2ecbe..6b66ac832d 100644
--- a/components/esm/loadgmst.hpp
+++ b/components/esm/loadgmst.hpp
@@ -18,13 +18,15 @@ class ESMWriter;
struct GameSetting
{
+ static unsigned int sRecordId;
+
std::string mId;
Variant mValue;
void load(ESMReader &esm);
- /// \todo remove the get* functions (redundant, since mValue as equivalent functions now).
+ /// \todo remove the get* functions (redundant, since mValue has equivalent functions now).
int getInt() const;
///< Throws an exception if GMST is not of type int or float.
@@ -35,7 +37,7 @@ struct GameSetting
std::string getString() const;
///< Throwns an exception if GMST is not of type string.
- void save(ESMWriter &esm);
+ void save(ESMWriter &esm) const;
void blank();
///< Set record to default state (does not touch the ID).
diff --git a/components/esm/loadinfo.cpp b/components/esm/loadinfo.cpp
index 90f8fcf35b..4f248cc65f 100644
--- a/components/esm/loadinfo.cpp
+++ b/components/esm/loadinfo.cpp
@@ -2,9 +2,11 @@
#include "esmreader.hpp"
#include "esmwriter.hpp"
+#include "defs.hpp"
namespace ESM
{
+ unsigned int DialInfo::sRecordId = REC_INFO;
void DialInfo::load(ESMReader &esm)
{
@@ -120,7 +122,7 @@ void DialInfo::load(ESMReader &esm)
esm.skipRecord();
}
-void DialInfo::save(ESMWriter &esm)
+void DialInfo::save(ESMWriter &esm) const
{
esm.writeHNCString("INAM", mId);
esm.writeHNCString("PNAM", mPrev);
@@ -135,7 +137,7 @@ void DialInfo::save(ESMWriter &esm)
esm.writeHNOCString("SNAM", mSound);
esm.writeHNOString("NAME", mResponse);
- for (std::vector<SelectStruct>::iterator it = mSelects.begin(); it != mSelects.end(); ++it)
+ for (std::vector<SelectStruct>::const_iterator it = mSelects.begin(); it != mSelects.end(); ++it)
{
esm.writeHNString("SCVR", it->mSelectRule);
it->mValue.write (esm, Variant::Format_Info);
diff --git a/components/esm/loadinfo.hpp b/components/esm/loadinfo.hpp
index 2361ed9eb5..2589ea7b87 100644
--- a/components/esm/loadinfo.hpp
+++ b/components/esm/loadinfo.hpp
@@ -20,6 +20,8 @@ class ESMWriter;
struct DialInfo
{
+ static unsigned int sRecordId;
+
enum Gender
{
Male = 0,
@@ -99,7 +101,7 @@ struct DialInfo
};
void load(ESMReader &esm);
- void save(ESMWriter &esm);
+ void save(ESMWriter &esm) const;
};
}
diff --git a/components/esm/loadingr.cpp b/components/esm/loadingr.cpp
index 7e31a4116d..0e02433621 100644
--- a/components/esm/loadingr.cpp
+++ b/components/esm/loadingr.cpp
@@ -2,9 +2,11 @@
#include "esmreader.hpp"
#include "esmwriter.hpp"
+#include "defs.hpp"
namespace ESM
{
+ unsigned int Ingredient::sRecordId = REC_INGR;
void Ingredient::load(ESMReader &esm)
{
@@ -37,7 +39,7 @@ void Ingredient::load(ESMReader &esm)
}
}
-void Ingredient::save(ESMWriter &esm)
+void Ingredient::save(ESMWriter &esm) const
{
esm.writeHNCString("MODL", mModel);
esm.writeHNCString("FNAM", mName);
diff --git a/components/esm/loadingr.hpp b/components/esm/loadingr.hpp
index 5e286535f4..85f2d5e7d2 100644
--- a/components/esm/loadingr.hpp
+++ b/components/esm/loadingr.hpp
@@ -15,6 +15,8 @@ class ESMWriter;
struct Ingredient
{
+ static unsigned int sRecordId;
+
struct IRDTstruct
{
float mWeight;
@@ -28,7 +30,7 @@ struct Ingredient
std::string mId, mName, mModel, mIcon, mScript;
void load(ESMReader &esm);
- void save(ESMWriter &esm);
+ void save(ESMWriter &esm) const;
void blank();
///< Set record to default state (does not touch the ID).
diff --git a/components/esm/loadland.cpp b/components/esm/loadland.cpp
index 60c475040f..ede200d79d 100644
--- a/components/esm/loadland.cpp
+++ b/components/esm/loadland.cpp
@@ -2,9 +2,11 @@
#include "esmreader.hpp"
#include "esmwriter.hpp"
+#include "defs.hpp"
namespace ESM
{
+ unsigned int Land::sRecordId = REC_LAND;
void Land::LandData::save(ESMWriter &esm)
{
@@ -16,14 +18,14 @@ void Land::LandData::save(ESMWriter &esm)
offsets.mHeightOffset = mHeights[0] / HEIGHT_SCALE;
offsets.mUnk1 = mUnk1;
offsets.mUnk2 = mUnk2;
-
+
float prevY = mHeights[0], prevX;
int number = 0; // avoid multiplication
for (int i = 0; i < LAND_SIZE; ++i) {
float diff = (mHeights[number] - prevY) / HEIGHT_SCALE;
offsets.mHeightData[number] =
(diff >= 0) ? (int8_t) (diff + 0.5) : (int8_t) (diff - 0.5);
-
+
prevX = prevY = mHeights[number];
++number;
@@ -132,7 +134,7 @@ void Land::load(ESMReader &esm)
mLandData = NULL;
}
-void Land::save(ESMWriter &esm)
+void Land::save(ESMWriter &esm) const
{
esm.startSubRecord("INTV");
esm.writeT(mX);
@@ -140,18 +142,6 @@ void Land::save(ESMWriter &esm)
esm.endRecord("INTV");
esm.writeHNT("DATA", mFlags);
-
- // TODO: Land!
- bool wasLoaded = mDataLoaded;
- if (mDataTypes) {
- // Try to load all available data before saving
- loadData(mDataTypes);
- }
- if (mDataLoaded)
- mLandData->save(esm);
-
- if (!wasLoaded)
- unloadData(); // Don't need to keep the data loaded if it wasn't already
}
/// \todo remove memory allocation when only defaults needed
diff --git a/components/esm/loadland.hpp b/components/esm/loadland.hpp
index 9c1fd1f5c6..5649f99801 100644
--- a/components/esm/loadland.hpp
+++ b/components/esm/loadland.hpp
@@ -17,6 +17,8 @@ class ESMWriter;
struct Land
{
+ static unsigned int sRecordId;
+
Land();
~Land();
@@ -94,7 +96,7 @@ struct Land
LandData *mLandData;
void load(ESMReader &esm);
- void save(ESMWriter &esm);
+ void save(ESMWriter &esm) const;
/**
* Actually loads data
diff --git a/components/esm/loadlevlist.cpp b/components/esm/loadlevlist.cpp
index b54a912760..6385b9a718 100644
--- a/components/esm/loadlevlist.cpp
+++ b/components/esm/loadlevlist.cpp
@@ -2,6 +2,7 @@
#include "esmreader.hpp"
#include "esmwriter.hpp"
+#include "defs.hpp"
namespace ESM
{
@@ -33,13 +34,13 @@ void LeveledListBase::load(ESMReader &esm)
esm.getHNT(li.mLevel, "INTV");
}
}
-void LeveledListBase::save(ESMWriter &esm)
+void LeveledListBase::save(ESMWriter &esm) const
{
esm.writeHNT("DATA", mFlags);
esm.writeHNT("NNAM", mChanceNone);
esm.writeHNT<int>("INDX", mList.size());
- for (std::vector<LevelItem>::iterator it = mList.begin(); it != mList.end(); ++it)
+ for (std::vector<LevelItem>::const_iterator it = mList.begin(); it != mList.end(); ++it)
{
esm.writeHNCString(mRecName, it->mId);
esm.writeHNT("INTV", it->mLevel);
@@ -52,4 +53,8 @@ void LeveledListBase::save(ESMWriter &esm)
mChanceNone = 0;
mList.clear();
}
+
+ unsigned int CreatureLevList::sRecordId = REC_LEVC;
+
+ unsigned int ItemLevList::sRecordId = REC_LEVI;
}
diff --git a/components/esm/loadlevlist.hpp b/components/esm/loadlevlist.hpp
index 7339cac56f..9dcc6177a1 100644
--- a/components/esm/loadlevlist.hpp
+++ b/components/esm/loadlevlist.hpp
@@ -51,7 +51,7 @@ struct LeveledListBase
std::vector<LevelItem> mList;
void load(ESMReader &esm);
- void save(ESMWriter &esm);
+ void save(ESMWriter &esm) const;
void blank();
///< Set record to default state (does not touch the ID).
@@ -59,6 +59,8 @@ struct LeveledListBase
struct CreatureLevList: LeveledListBase
{
+ static unsigned int sRecordId;
+
CreatureLevList()
{
mRecName = "CNAM";
@@ -67,6 +69,8 @@ struct CreatureLevList: LeveledListBase
struct ItemLevList: LeveledListBase
{
+ static unsigned int sRecordId;
+
ItemLevList()
{
mRecName = "INAM";
diff --git a/components/esm/loadligh.cpp b/components/esm/loadligh.cpp
index 89a2b8c65b..c02bb46b69 100644
--- a/components/esm/loadligh.cpp
+++ b/components/esm/loadligh.cpp
@@ -2,9 +2,11 @@
#include "esmreader.hpp"
#include "esmwriter.hpp"
+#include "defs.hpp"
namespace ESM
{
+ unsigned int Light::sRecordId = REC_LIGH;
void Light::load(ESMReader &esm)
{
@@ -16,7 +18,7 @@ void Light::load(ESMReader &esm)
mScript = esm.getHNOString("SCRI");
mSound = esm.getHNOString("SNAM");
}
-void Light::save(ESMWriter &esm)
+void Light::save(ESMWriter &esm) const
{
esm.writeHNCString("MODL", mModel);
esm.writeHNOCString("FNAM", mName);
diff --git a/components/esm/loadligh.hpp b/components/esm/loadligh.hpp
index 3f0b76d6e2..74eb37197e 100644
--- a/components/esm/loadligh.hpp
+++ b/components/esm/loadligh.hpp
@@ -16,6 +16,8 @@ class ESMWriter;
struct Light
{
+ static unsigned int sRecordId;
+
enum Flags
{
Dynamic = 0x001,
@@ -44,7 +46,7 @@ struct Light
std::string mSound, mScript, mModel, mIcon, mName, mId;
void load(ESMReader &esm);
- void save(ESMWriter &esm);
+ void save(ESMWriter &esm) const;
void blank();
///< Set record to default state (does not touch the ID).
diff --git a/components/esm/loadlock.cpp b/components/esm/loadlock.cpp
index 03eac52bd5..9ffce78a7d 100644
--- a/components/esm/loadlock.cpp
+++ b/components/esm/loadlock.cpp
@@ -2,9 +2,11 @@
#include "esmreader.hpp"
#include "esmwriter.hpp"
+#include "defs.hpp"
namespace ESM
{
+ unsigned int Lockpick::sRecordId = REC_LOCK;
void Lockpick::load(ESMReader &esm)
{
@@ -17,7 +19,7 @@ void Lockpick::load(ESMReader &esm)
mIcon = esm.getHNOString("ITEX");
}
-void Lockpick::save(ESMWriter &esm)
+void Lockpick::save(ESMWriter &esm) const
{
esm.writeHNCString("MODL", mModel);
esm.writeHNCString("FNAM", mName);
diff --git a/components/esm/loadlock.hpp b/components/esm/loadlock.hpp
index 953066cb2f..c44e2b0063 100644
--- a/components/esm/loadlock.hpp
+++ b/components/esm/loadlock.hpp
@@ -11,6 +11,8 @@ class ESMWriter;
struct Lockpick
{
+ static unsigned int sRecordId;
+
struct Data
{
float mWeight;
@@ -24,7 +26,7 @@ struct Lockpick
std::string mId, mName, mModel, mIcon, mScript;
void load(ESMReader &esm);
- void save(ESMWriter &esm);
+ void save(ESMWriter &esm) const;
void blank();
///< Set record to default state (does not touch the ID).
diff --git a/components/esm/loadltex.cpp b/components/esm/loadltex.cpp
index e523e9fa7f..bd28c84883 100644
--- a/components/esm/loadltex.cpp
+++ b/components/esm/loadltex.cpp
@@ -2,16 +2,18 @@
#include "esmreader.hpp"
#include "esmwriter.hpp"
+#include "defs.hpp"
namespace ESM
{
+ unsigned int LandTexture::sRecordId = REC_LTEX;
void LandTexture::load(ESMReader &esm)
{
esm.getHNT(mIndex, "INTV");
mTexture = esm.getHNString("DATA");
}
-void LandTexture::save(ESMWriter &esm)
+void LandTexture::save(ESMWriter &esm) const
{
esm.writeHNT("INTV", mIndex);
esm.writeHNCString("DATA", mTexture);
diff --git a/components/esm/loadltex.hpp b/components/esm/loadltex.hpp
index 6e6d987d49..5e84428b29 100644
--- a/components/esm/loadltex.hpp
+++ b/components/esm/loadltex.hpp
@@ -27,11 +27,13 @@ class ESMWriter;
struct LandTexture
{
+ static unsigned int sRecordId;
+
std::string mId, mTexture;
int mIndex;
void load(ESMReader &esm);
- void save(ESMWriter &esm);
+ void save(ESMWriter &esm) const;
};
}
#endif
diff --git a/components/esm/loadmgef.cpp b/components/esm/loadmgef.cpp
index 060645b5f4..1a90f5b09c 100644
--- a/components/esm/loadmgef.cpp
+++ b/components/esm/loadmgef.cpp
@@ -6,6 +6,7 @@
#include "esmreader.hpp"
#include "esmwriter.hpp"
+#include "defs.hpp"
namespace
{
@@ -34,6 +35,7 @@ namespace
namespace ESM
{
+ unsigned int MagicEffect::sRecordId = REC_MGEF;
void MagicEffect::load(ESMReader &esm)
{
@@ -58,15 +60,11 @@ void MagicEffect::load(ESMReader &esm)
mDescription = esm.getHNOString("DESC");
}
-void MagicEffect::save(ESMWriter &esm)
+void MagicEffect::save(ESMWriter &esm) const
{
esm.writeHNT("INDX", mIndex);
- mData.mFlags &= 0xe00;
esm.writeHNT("MEDT", mData, 36);
- if (mIndex>=0 && mIndex<NumberOfHardcodedFlags) {
- mData.mFlags |= HardcodedFlags[mIndex];
- }
esm.writeHNOCString("ITEX", mIcon);
esm.writeHNOCString("PTEX", mParticle);
@@ -74,12 +72,12 @@ void MagicEffect::save(ESMWriter &esm)
esm.writeHNOCString("CSND", mCastSound);
esm.writeHNOCString("HSND", mHitSound);
esm.writeHNOCString("ASND", mAreaSound);
-
+
esm.writeHNOCString("CVFX", mCasting);
esm.writeHNOCString("BVFX", mBolt);
esm.writeHNOCString("HVFX", mHit);
esm.writeHNOCString("AVFX", mArea);
-
+
esm.writeHNOString("DESC", mDescription);
}
@@ -274,5 +272,23 @@ short MagicEffect::effectStringToId(const std::string &effect)
return name->first;
}
+MagicEffect::MagnitudeDisplayType MagicEffect::getMagnitudeDisplayType() const {
+ if ( mData.mFlags & NoMagnitude )
+ return MDT_None;
+ if ( mIndex == 84 )
+ return MDT_TimesInt;
+ if ( mIndex == 59 ||
+ ( mIndex >= 64 && mIndex <= 66) )
+ return MDT_Feet;
+ if ( mIndex == 118 || mIndex == 119 )
+ return MDT_Level;
+ if ( ( mIndex >= 28 && mIndex <= 36 )
+ || ( mIndex >= 90 && mIndex <= 99 )
+ || mIndex == 40 || mIndex == 47
+ || mIndex == 57 || mIndex == 68 )
+ return MDT_Percentage;
+
+ return MDT_Points;
+}
}
diff --git a/components/esm/loadmgef.hpp b/components/esm/loadmgef.hpp
index b74efb4662..9d7397a341 100644
--- a/components/esm/loadmgef.hpp
+++ b/components/esm/loadmgef.hpp
@@ -12,6 +12,8 @@ class ESMWriter;
struct MagicEffect
{
+ static unsigned int sRecordId;
+
enum Flags
{
TargetSkill = 0x1, // Affects a specific skill, which is specified elsewhere in the effect structure.
@@ -32,6 +34,15 @@ struct MagicEffect
Negative = 0x0800 // A harmful effect. Will determine whether
// eg. NPCs regard this spell as an attack. (same as 0x10?)
};
+ enum MagnitudeDisplayType
+ {
+ MDT_None,
+ MDT_Feet,
+ MDT_Level,
+ MDT_Percentage,
+ MDT_Points,
+ MDT_TimesInt
+ };
struct MEDTstruct
{
@@ -47,6 +58,7 @@ struct MagicEffect
static const std::string &effectIdToString(short effectID);
static short effectStringToId(const std::string &effect);
+ MagnitudeDisplayType getMagnitudeDisplayType() const;
MEDTstruct mData;
@@ -69,7 +81,7 @@ struct MagicEffect
int mIndex;
void load(ESMReader &esm);
- void save(ESMWriter &esm);
+ void save(ESMWriter &esm) const;
enum Effects
diff --git a/components/esm/loadmisc.cpp b/components/esm/loadmisc.cpp
index 6006334ea4..2ca09e8aec 100644
--- a/components/esm/loadmisc.cpp
+++ b/components/esm/loadmisc.cpp
@@ -2,9 +2,11 @@
#include "esmreader.hpp"
#include "esmwriter.hpp"
+#include "defs.hpp"
namespace ESM
{
+ unsigned int Miscellaneous::sRecordId = REC_MISC;
void Miscellaneous::load(ESMReader &esm)
{
@@ -14,7 +16,7 @@ void Miscellaneous::load(ESMReader &esm)
mScript = esm.getHNOString("SCRI");
mIcon = esm.getHNOString("ITEX");
}
-void Miscellaneous::save(ESMWriter &esm)
+void Miscellaneous::save(ESMWriter &esm) const
{
esm.writeHNCString("MODL", mModel);
esm.writeHNOCString("FNAM", mName);
diff --git a/components/esm/loadmisc.hpp b/components/esm/loadmisc.hpp
index 25a9c5865a..576bd18c0f 100644
--- a/components/esm/loadmisc.hpp
+++ b/components/esm/loadmisc.hpp
@@ -16,6 +16,8 @@ class ESMWriter;
struct Miscellaneous
{
+ static unsigned int sRecordId;
+
struct MCDTstruct
{
float mWeight;
@@ -29,7 +31,7 @@ struct Miscellaneous
std::string mId, mName, mModel, mIcon, mScript;
void load(ESMReader &esm);
- void save(ESMWriter &esm);
+ void save(ESMWriter &esm) const;
void blank();
///< Set record to default state (does not touch the ID).
diff --git a/components/esm/loadnpc.cpp b/components/esm/loadnpc.cpp
index 7e17a93dc6..9fff2d885d 100644
--- a/components/esm/loadnpc.cpp
+++ b/components/esm/loadnpc.cpp
@@ -2,9 +2,11 @@
#include "esmreader.hpp"
#include "esmwriter.hpp"
+#include "defs.hpp"
namespace ESM
{
+ unsigned int NPC::sRecordId = REC_NPC_;
void NPC::load(ESMReader &esm)
{
@@ -63,7 +65,7 @@ void NPC::load(ESMReader &esm)
mAiPackage.load(esm);
esm.skipRecord();
}
-void NPC::save(ESMWriter &esm)
+void NPC::save(ESMWriter &esm) const
{
esm.writeHNOCString("MODL", mModel);
esm.writeHNOCString("FNAM", mName);
@@ -87,7 +89,7 @@ void NPC::save(ESMWriter &esm)
esm.writeHNT("AIDT", mAiData, sizeof(mAiData));
}
- typedef std::vector<Dest>::iterator DestIter;
+ typedef std::vector<Dest>::const_iterator DestIter;
for (DestIter it = mTransport.begin(); it != mTransport.end(); ++it) {
esm.writeHNT("DODT", it->mPos, sizeof(it->mPos));
esm.writeHNOCString("DNAM", it->mCellName);
diff --git a/components/esm/loadnpc.hpp b/components/esm/loadnpc.hpp
index 009bc5ef3b..d9e691669c 100644
--- a/components/esm/loadnpc.hpp
+++ b/components/esm/loadnpc.hpp
@@ -20,6 +20,8 @@ class ESMWriter;
struct NPC
{
+ static unsigned int sRecordId;
+
// Services
enum Services
{
@@ -117,7 +119,7 @@ struct NPC
std::string mHair, mHead;
void load(ESMReader &esm);
- void save(ESMWriter &esm);
+ void save(ESMWriter &esm) const;
bool isMale() const;
diff --git a/components/esm/loadnpcc.hpp b/components/esm/loadnpcc.hpp
index 79d92397f8..c87c2545f7 100644
--- a/components/esm/loadnpcc.hpp
+++ b/components/esm/loadnpcc.hpp
@@ -78,13 +78,15 @@ class ESMWriter;
struct LoadNPCC
{
+ static unsigned int sRecordId;
+
std::string mId;
void load(ESMReader &esm)
{
esm.skipRecord();
}
- void save(ESMWriter &esm)
+ void save(ESMWriter &esm) const
{
}
};
diff --git a/components/esm/loadpgrd.cpp b/components/esm/loadpgrd.cpp
index 882addcb9d..3b5330e9fd 100644
--- a/components/esm/loadpgrd.cpp
+++ b/components/esm/loadpgrd.cpp
@@ -2,9 +2,11 @@
#include "esmreader.hpp"
#include "esmwriter.hpp"
+#include "defs.hpp"
namespace ESM
{
+ unsigned int Pathgrid::sRecordId = REC_PGRD;
void Pathgrid::load(ESMReader &esm)
{
@@ -70,25 +72,25 @@ void Pathgrid::load(ESMReader &esm)
}
}
}
-void Pathgrid::save(ESMWriter &esm)
+void Pathgrid::save(ESMWriter &esm) const
{
esm.writeHNT("DATA", mData, 12);
esm.writeHNCString("NAME", mCell);
-
+
if (!mPoints.empty())
{
esm.startSubRecord("PGRP");
- for (PointList::iterator it = mPoints.begin(); it != mPoints.end(); ++it)
+ for (PointList::const_iterator it = mPoints.begin(); it != mPoints.end(); ++it)
{
esm.writeT(*it);
}
esm.endRecord("PGRP");
}
-
+
if (!mEdges.empty())
{
esm.startSubRecord("PGRC");
- for (std::vector<Edge>::iterator it = mEdges.begin(); it != mEdges.end(); ++it)
+ for (std::vector<Edge>::const_iterator it = mEdges.begin(); it != mEdges.end(); ++it)
{
esm.writeT(it->mV1);
}
diff --git a/components/esm/loadpgrd.hpp b/components/esm/loadpgrd.hpp
index c3f50fc4da..9ee49552db 100644
--- a/components/esm/loadpgrd.hpp
+++ b/components/esm/loadpgrd.hpp
@@ -15,6 +15,8 @@ class ESMWriter;
*/
struct Pathgrid
{
+ static unsigned int sRecordId;
+
struct DATAstruct
{
int mX, mY; // Grid location, matches cell for exterior cells
@@ -46,7 +48,7 @@ struct Pathgrid
EdgeList mEdges;
void load(ESMReader &esm);
- void save(ESMWriter &esm);
+ void save(ESMWriter &esm) const;
};
}
#endif
diff --git a/components/esm/loadprob.cpp b/components/esm/loadprob.cpp
index 729f8404e5..caa3d7e0e7 100644
--- a/components/esm/loadprob.cpp
+++ b/components/esm/loadprob.cpp
@@ -2,9 +2,11 @@
#include "esmreader.hpp"
#include "esmwriter.hpp"
+#include "defs.hpp"
namespace ESM
{
+ unsigned int Probe::sRecordId = REC_PROB;
void Probe::load(ESMReader &esm)
{
@@ -17,7 +19,7 @@ void Probe::load(ESMReader &esm)
mIcon = esm.getHNOString("ITEX");
}
-void Probe::save(ESMWriter &esm)
+void Probe::save(ESMWriter &esm) const
{
esm.writeHNCString("MODL", mModel);
esm.writeHNCString("FNAM", mName);
diff --git a/components/esm/loadprob.hpp b/components/esm/loadprob.hpp
index 55b896bcda..b89b2ddeb6 100644
--- a/components/esm/loadprob.hpp
+++ b/components/esm/loadprob.hpp
@@ -11,6 +11,8 @@ class ESMWriter;
struct Probe
{
+ static unsigned int sRecordId;
+
struct Data
{
float mWeight;
@@ -24,7 +26,7 @@ struct Probe
std::string mId, mName, mModel, mIcon, mScript;
void load(ESMReader &esm);
- void save(ESMWriter &esm);
+ void save(ESMWriter &esm) const;
void blank();
///< Set record to default state (does not touch the ID).
diff --git a/components/esm/loadrace.cpp b/components/esm/loadrace.cpp
index 955424e2b9..e50e43a744 100644
--- a/components/esm/loadrace.cpp
+++ b/components/esm/loadrace.cpp
@@ -2,9 +2,12 @@
#include "esmreader.hpp"
#include "esmwriter.hpp"
+#include "defs.hpp"
namespace ESM
{
+ unsigned int Race::sRecordId = REC_RACE;
+
int Race::MaleFemale::getValue (bool male) const
{
return male ? mMale : mFemale;
@@ -22,7 +25,7 @@ void Race::load(ESMReader &esm)
mPowers.load(esm);
mDescription = esm.getHNOString("DESC");
}
-void Race::save(ESMWriter &esm)
+void Race::save(ESMWriter &esm) const
{
esm.writeHNCString("FNAM", mName);
esm.writeHNT("RADT", mData, 140);
diff --git a/components/esm/loadrace.hpp b/components/esm/loadrace.hpp
index 6ecec8ebb9..7d5736d9b7 100644
--- a/components/esm/loadrace.hpp
+++ b/components/esm/loadrace.hpp
@@ -17,6 +17,8 @@ class ESMWriter;
struct Race
{
+ static unsigned int sRecordId;
+
struct SkillBonus
{
int mSkill; // SkillEnum
@@ -65,7 +67,7 @@ struct Race
SpellList mPowers;
void load(ESMReader &esm);
- void save(ESMWriter &esm);
+ void save(ESMWriter &esm) const;
void blank();
///< Set record to default state (does not touch the ID/index).
diff --git a/components/esm/loadregn.cpp b/components/esm/loadregn.cpp
index 41c7f507ae..fa4271e26a 100644
--- a/components/esm/loadregn.cpp
+++ b/components/esm/loadregn.cpp
@@ -2,9 +2,11 @@
#include "esmreader.hpp"
#include "esmwriter.hpp"
+#include "defs.hpp"
namespace ESM
{
+ unsigned int Region::sRecordId = REC_REGN;
void Region::load(ESMReader &esm)
{
@@ -28,7 +30,7 @@ void Region::load(ESMReader &esm)
mSoundList.push_back(sr);
}
}
-void Region::save(ESMWriter &esm)
+void Region::save(ESMWriter &esm) const
{
esm.writeHNCString("FNAM", mName);
@@ -40,7 +42,7 @@ void Region::save(ESMWriter &esm)
esm.writeHNOCString("BNAM", mSleepList);
esm.writeHNT("CNAM", mMapColor);
- for (std::vector<SoundRef>::iterator it = mSoundList.begin(); it != mSoundList.end(); ++it)
+ for (std::vector<SoundRef>::const_iterator it = mSoundList.begin(); it != mSoundList.end(); ++it)
{
esm.writeHNT<SoundRef>("SNAM", *it);
}
diff --git a/components/esm/loadregn.hpp b/components/esm/loadregn.hpp
index f2a3d9a108..1992c951b4 100644
--- a/components/esm/loadregn.hpp
+++ b/components/esm/loadregn.hpp
@@ -18,6 +18,8 @@ class ESMWriter;
struct Region
{
+ static unsigned int sRecordId;
+
#pragma pack(push)
#pragma pack(1)
struct WEATstruct
@@ -47,7 +49,7 @@ struct Region
std::vector<SoundRef> mSoundList;
void load(ESMReader &esm);
- void save(ESMWriter &esm);
+ void save(ESMWriter &esm) const;
void blank();
///< Set record to default state (does not touch the ID/index).
diff --git a/components/esm/loadrepa.cpp b/components/esm/loadrepa.cpp
index ced6daa2e9..a7132828d4 100644
--- a/components/esm/loadrepa.cpp
+++ b/components/esm/loadrepa.cpp
@@ -2,9 +2,11 @@
#include "esmreader.hpp"
#include "esmwriter.hpp"
+#include "defs.hpp"
namespace ESM
{
+ unsigned int Repair::sRecordId = REC_REPA;
void Repair::load(ESMReader &esm)
{
@@ -17,7 +19,7 @@ void Repair::load(ESMReader &esm)
mIcon = esm.getHNOString("ITEX");
}
-void Repair::save(ESMWriter &esm)
+void Repair::save(ESMWriter &esm) const
{
esm.writeHNCString("MODL", mModel);
esm.writeHNCString("FNAM", mName);
diff --git a/components/esm/loadrepa.hpp b/components/esm/loadrepa.hpp
index 83812bad9c..5b404b0e4c 100644
--- a/components/esm/loadrepa.hpp
+++ b/components/esm/loadrepa.hpp
@@ -11,6 +11,8 @@ class ESMWriter;
struct Repair
{
+ static unsigned int sRecordId;
+
struct Data
{
float mWeight;
@@ -24,7 +26,7 @@ struct Repair
std::string mId, mName, mModel, mIcon, mScript;
void load(ESMReader &esm);
- void save(ESMWriter &esm);
+ void save(ESMWriter &esm) const;
void blank();
///< Set record to default state (does not touch the ID).
diff --git a/components/esm/loadscpt.cpp b/components/esm/loadscpt.cpp
index 2c1b018d97..30460c17a6 100644
--- a/components/esm/loadscpt.cpp
+++ b/components/esm/loadscpt.cpp
@@ -2,6 +2,7 @@
#include "esmreader.hpp"
#include "esmwriter.hpp"
+#include "defs.hpp"
namespace ESM
{
@@ -12,6 +13,8 @@ struct SCHD
Script::SCHDstruct mData;
};
+ unsigned int Script::sRecordId = REC_SCPT;
+
void Script::load(ESMReader &esm)
{
SCHD data;
@@ -50,11 +53,11 @@ void Script::load(ESMReader &esm)
// Script text
mScriptText = esm.getHNOString("SCTX");
}
-void Script::save(ESMWriter &esm)
+void Script::save(ESMWriter &esm) const
{
std::string varNameString;
if (!mVarNames.empty())
- for (std::vector<std::string>::iterator it = mVarNames.begin(); it != mVarNames.end(); ++it)
+ for (std::vector<std::string>::const_iterator it = mVarNames.begin(); it != mVarNames.end(); ++it)
varNameString.append(*it);
SCHD data;
@@ -68,7 +71,7 @@ void Script::save(ESMWriter &esm)
if (!mVarNames.empty())
{
esm.startSubRecord("SCVR");
- for (std::vector<std::string>::iterator it = mVarNames.begin(); it != mVarNames.end(); ++it)
+ for (std::vector<std::string>::const_iterator it = mVarNames.begin(); it != mVarNames.end(); ++it)
{
esm.writeHCString(*it);
}
diff --git a/components/esm/loadscpt.hpp b/components/esm/loadscpt.hpp
index be7e839002..d5200d4c12 100644
--- a/components/esm/loadscpt.hpp
+++ b/components/esm/loadscpt.hpp
@@ -19,6 +19,8 @@ class ESMWriter;
class Script
{
public:
+ static unsigned int sRecordId;
+
struct SCHDstruct
{
/* Script name.
@@ -56,7 +58,7 @@ public:
std::string mScriptText; // Uncompiled script
void load(ESMReader &esm);
- void save(ESMWriter &esm);
+ void save(ESMWriter &esm) const;
void blank();
///< Set record to default state (does not touch the ID/index).
diff --git a/components/esm/loadskil.cpp b/components/esm/loadskil.cpp
index 676a835c3b..b6724e9381 100644
--- a/components/esm/loadskil.cpp
+++ b/components/esm/loadskil.cpp
@@ -6,6 +6,7 @@
#include "esmreader.hpp"
#include "esmwriter.hpp"
+#include "defs.hpp"
namespace ESM
{
@@ -126,6 +127,8 @@ namespace ESM
HandToHand
}};
+ unsigned int Skill::sRecordId = REC_SKIL;
+
void Skill::load(ESMReader &esm)
{
esm.getHNT(mIndex, "INDX");
@@ -137,7 +140,7 @@ void Skill::load(ESMReader &esm)
mId = indexToId (mIndex);
}
-void Skill::save(ESMWriter &esm)
+void Skill::save(ESMWriter &esm) const
{
esm.writeHNT("INDX", mIndex);
esm.writeHNT("SKDT", mData, 24);
diff --git a/components/esm/loadskil.hpp b/components/esm/loadskil.hpp
index 384f874545..1b9db5bcff 100644
--- a/components/esm/loadskil.hpp
+++ b/components/esm/loadskil.hpp
@@ -19,6 +19,8 @@ class ESMWriter;
struct Skill
{
+ static unsigned int sRecordId;
+
std::string mId;
struct SKDTstruct
@@ -75,7 +77,7 @@ struct Skill
static const boost::array<SkillEnum, Length> sSkillIds;
void load(ESMReader &esm);
- void save(ESMWriter &esm);
+ void save(ESMWriter &esm) const;
void blank();
///< Set record to default state (does not touch the ID/index).
diff --git a/components/esm/loadsndg.cpp b/components/esm/loadsndg.cpp
index 42d524226d..1a8ca63354 100644
--- a/components/esm/loadsndg.cpp
+++ b/components/esm/loadsndg.cpp
@@ -2,9 +2,11 @@
#include "esmreader.hpp"
#include "esmwriter.hpp"
+#include "defs.hpp"
namespace ESM
{
+ unsigned int SoundGenerator::sRecordId = REC_SNDG;
void SoundGenerator::load(ESMReader &esm)
{
@@ -13,7 +15,7 @@ void SoundGenerator::load(ESMReader &esm)
mCreature = esm.getHNOString("CNAM");
mSound = esm.getHNOString("SNAM");
}
-void SoundGenerator::save(ESMWriter &esm)
+void SoundGenerator::save(ESMWriter &esm) const
{
esm.writeHNT("DATA", mType, 4);
esm.writeHNOCString("CNAM", mCreature);
diff --git a/components/esm/loadsndg.hpp b/components/esm/loadsndg.hpp
index a6226c1545..5509661c18 100644
--- a/components/esm/loadsndg.hpp
+++ b/components/esm/loadsndg.hpp
@@ -15,6 +15,8 @@ class ESMWriter;
struct SoundGenerator
{
+ static unsigned int sRecordId;
+
enum Type
{
LeftFoot = 0,
@@ -33,7 +35,7 @@ struct SoundGenerator
std::string mId, mCreature, mSound;
void load(ESMReader &esm);
- void save(ESMWriter &esm);
+ void save(ESMWriter &esm) const;
};
}
#endif
diff --git a/components/esm/loadsoun.cpp b/components/esm/loadsoun.cpp
index 07af2b5e91..49c9eb54e2 100644
--- a/components/esm/loadsoun.cpp
+++ b/components/esm/loadsoun.cpp
@@ -2,9 +2,11 @@
#include "esmreader.hpp"
#include "esmwriter.hpp"
+#include "defs.hpp"
namespace ESM
{
+ unsigned int Sound::sRecordId = REC_SOUN;
void Sound::load(ESMReader &esm)
{
@@ -17,7 +19,7 @@ void Sound::load(ESMReader &esm)
<< endl;
*/
}
-void Sound::save(ESMWriter &esm)
+void Sound::save(ESMWriter &esm) const
{
esm.writeHNCString("FNAM", mSound);
esm.writeHNT("DATA", mData, 3);
diff --git a/components/esm/loadsoun.hpp b/components/esm/loadsoun.hpp
index f8e38ac092..04a0984fda 100644
--- a/components/esm/loadsoun.hpp
+++ b/components/esm/loadsoun.hpp
@@ -16,11 +16,13 @@ struct SOUNstruct
struct Sound
{
+ static unsigned int sRecordId;
+
SOUNstruct mData;
std::string mId, mSound;
void load(ESMReader &esm);
- void save(ESMWriter &esm);
+ void save(ESMWriter &esm) const;
void blank();
///< Set record to default state (does not touch the ID/index).
diff --git a/components/esm/loadspel.cpp b/components/esm/loadspel.cpp
index 8149fe4cef..2c98d796d3 100644
--- a/components/esm/loadspel.cpp
+++ b/components/esm/loadspel.cpp
@@ -2,9 +2,11 @@
#include "esmreader.hpp"
#include "esmwriter.hpp"
+#include "defs.hpp"
namespace ESM
{
+ unsigned int Spell::sRecordId = REC_SPEL;
void Spell::load(ESMReader &esm)
{
@@ -13,7 +15,7 @@ void Spell::load(ESMReader &esm)
mEffects.load(esm);
}
-void Spell::save(ESMWriter &esm)
+void Spell::save(ESMWriter &esm) const
{
esm.writeHNOCString("FNAM", mName);
esm.writeHNT("SPDT", mData, 12);
diff --git a/components/esm/loadspel.hpp b/components/esm/loadspel.hpp
index 3a620962d1..cbf5366c4b 100644
--- a/components/esm/loadspel.hpp
+++ b/components/esm/loadspel.hpp
@@ -13,6 +13,8 @@ class ESMWriter;
struct Spell
{
+ static unsigned int sRecordId;
+
enum SpellType
{
ST_Spell = 0, // Normal spell, must be cast and costs mana
@@ -42,7 +44,7 @@ struct Spell
EffectList mEffects;
void load(ESMReader &esm);
- void save(ESMWriter &esm);
+ void save(ESMWriter &esm) const;
void blank();
///< Set record to default state (does not touch the ID/index).
diff --git a/components/esm/loadsscr.cpp b/components/esm/loadsscr.cpp
index ae50de517c..69b04bb237 100644
--- a/components/esm/loadsscr.cpp
+++ b/components/esm/loadsscr.cpp
@@ -2,16 +2,18 @@
#include "esmreader.hpp"
#include "esmwriter.hpp"
+#include "defs.hpp"
namespace ESM
{
+ unsigned int StartScript::sRecordId = REC_SSCR;
void StartScript::load(ESMReader &esm)
{
mData = esm.getHNString("DATA");
mScript = esm.getHNString("NAME");
}
-void StartScript::save(ESMWriter &esm)
+void StartScript::save(ESMWriter &esm) const
{
esm.writeHNString("DATA", mData);
esm.writeHNString("NAME", mScript);
diff --git a/components/esm/loadsscr.hpp b/components/esm/loadsscr.hpp
index 713fe96b52..d09ad883eb 100644
--- a/components/esm/loadsscr.hpp
+++ b/components/esm/loadsscr.hpp
@@ -19,12 +19,14 @@ class ESMWriter;
struct StartScript
{
+ static unsigned int sRecordId;
+
std::string mData;
std::string mId, mScript;
// Load a record and add it to the list
void load(ESMReader &esm);
- void save(ESMWriter &esm);
+ void save(ESMWriter &esm) const;
};
}
diff --git a/components/esm/loadstat.cpp b/components/esm/loadstat.cpp
index c9346dafca..a71f22dc23 100644
--- a/components/esm/loadstat.cpp
+++ b/components/esm/loadstat.cpp
@@ -2,15 +2,17 @@
#include "esmreader.hpp"
#include "esmwriter.hpp"
+#include "defs.hpp"
namespace ESM
{
+ unsigned int Static::sRecordId = REC_STAT;
void Static::load(ESMReader &esm)
{
mModel = esm.getHNString("MODL");
}
-void Static::save(ESMWriter &esm)
+void Static::save(ESMWriter &esm) const
{
esm.writeHNCString("MODL", mModel);
}
diff --git a/components/esm/loadstat.hpp b/components/esm/loadstat.hpp
index 1adb7d05be..d912d10583 100644
--- a/components/esm/loadstat.hpp
+++ b/components/esm/loadstat.hpp
@@ -22,10 +22,12 @@ class ESMWriter;
struct Static
{
+ static unsigned int sRecordId;
+
std::string mId, mModel;
void load(ESMReader &esm);
- void save(ESMWriter &esm);
+ void save(ESMWriter &esm) const;
void blank();
///< Set record to default state (does not touch the ID).
diff --git a/components/esm/loadtes3.cpp b/components/esm/loadtes3.cpp
index 74d578ba7d..87a8d1d57e 100644
--- a/components/esm/loadtes3.cpp
+++ b/components/esm/loadtes3.cpp
@@ -4,6 +4,7 @@
#include "esmcommon.hpp"
#include "esmreader.hpp"
#include "esmwriter.hpp"
+#include "defs.hpp"
void ESM::Header::blank()
{
@@ -13,6 +14,7 @@ void ESM::Header::blank()
mData.desc.assign ("");
mData.records = 0;
mFormat = CurrentFormat;
+ mMaster.clear();
}
void ESM::Header::load (ESMReader &esm)
diff --git a/components/esm/loadtes3.hpp b/components/esm/loadtes3.hpp
index b73a4c31e4..5614d295f6 100644
--- a/components/esm/loadtes3.hpp
+++ b/components/esm/loadtes3.hpp
@@ -24,7 +24,7 @@ namespace ESM
versions are 1.2 and 1.3. These correspond to:
1.2 = 0x3f99999a and 1.3 = 0x3fa66666
*/
- int version;
+ unsigned int version;
int type; // 0=esp, 1=esm, 32=ess (unused)
NAME32 author; // Author's name
NAME256 desc; // File description
diff --git a/components/esm/loadweap.cpp b/components/esm/loadweap.cpp
index 2537123969..1d0b149df1 100644
--- a/components/esm/loadweap.cpp
+++ b/components/esm/loadweap.cpp
@@ -2,9 +2,11 @@
#include "esmreader.hpp"
#include "esmwriter.hpp"
+#include "defs.hpp"
namespace ESM
{
+ unsigned int Weapon::sRecordId = REC_WEAP;
void Weapon::load(ESMReader &esm)
{
@@ -15,7 +17,7 @@ void Weapon::load(ESMReader &esm)
mIcon = esm.getHNOString("ITEX");
mEnchant = esm.getHNOString("ENAM");
}
-void Weapon::save(ESMWriter &esm)
+void Weapon::save(ESMWriter &esm) const
{
esm.writeHNCString("MODL", mModel);
esm.writeHNOCString("FNAM", mName);
diff --git a/components/esm/loadweap.hpp b/components/esm/loadweap.hpp
index b62179ccb1..fde716b916 100644
--- a/components/esm/loadweap.hpp
+++ b/components/esm/loadweap.hpp
@@ -15,6 +15,8 @@ class ESMWriter;
struct Weapon
{
+ static unsigned int sRecordId;
+
enum Type
{
ShortBladeOneHand = 0,
@@ -59,7 +61,7 @@ struct Weapon
std::string mId, mName, mModel, mIcon, mEnchant, mScript;
void load(ESMReader &esm);
- void save(ESMWriter &esm);
+ void save(ESMWriter &esm) const;
void blank();
///< Set record to default state (does not touch the ID).
diff --git a/components/esm/spelllist.cpp b/components/esm/spelllist.cpp
index dd886cf7ff..24d3c3d0a5 100644
--- a/components/esm/spelllist.cpp
+++ b/components/esm/spelllist.cpp
@@ -12,9 +12,9 @@ void SpellList::load(ESMReader &esm)
}
}
-void SpellList::save(ESMWriter &esm)
+void SpellList::save(ESMWriter &esm) const
{
- for (std::vector<std::string>::iterator it = mList.begin(); it != mList.end(); ++it) {
+ for (std::vector<std::string>::const_iterator it = mList.begin(); it != mList.end(); ++it) {
esm.writeHNString("NPCS", *it, 32);
}
}
diff --git a/components/esm/spelllist.hpp b/components/esm/spelllist.hpp
index 52999270a0..934bdda7ad 100644
--- a/components/esm/spelllist.hpp
+++ b/components/esm/spelllist.hpp
@@ -17,7 +17,7 @@ namespace ESM
std::vector<std::string> mList;
void load(ESMReader &esm);
- void save(ESMWriter &esm);
+ void save(ESMWriter &esm) const;
};
}
diff --git a/components/esm/variant.hpp b/components/esm/variant.hpp
index 8c5f3b3d47..2bba60a152 100644
--- a/components/esm/variant.hpp
+++ b/components/esm/variant.hpp
@@ -11,7 +11,7 @@ namespace ESM
enum VarType
{
- VT_Unknown,
+ VT_Unknown = 0,
VT_None,
VT_Short, // stored as a float, kinda
VT_Int,
diff --git a/components/esm/variantimp.cpp b/components/esm/variantimp.cpp
index 160402aa4b..1bacdc0770 100644
--- a/components/esm/variantimp.cpp
+++ b/components/esm/variantimp.cpp
@@ -193,7 +193,7 @@ void ESM::VariantIntegerData::write (ESMWriter& esm, Variant::Format format, Var
}
else if (format==Variant::Format_Gmst || format==Variant::Format_Info)
{
- if (type==VT_Int)
+ if (type!=VT_Int)
{
std::ostringstream stream;
stream
diff --git a/components/fileorderlist/model/datafilesmodel.cpp b/components/fileorderlist/model/datafilesmodel.cpp
deleted file mode 100644
index 02a6766b02..0000000000
--- a/components/fileorderlist/model/datafilesmodel.cpp
+++ /dev/null
@@ -1,445 +0,0 @@
-#include <QTextDecoder>
-#include <QTextCodec>
-#include <QFileInfo>
-#include <QDir>
-
-#include <stdexcept>
-
-#include <components/esm/esmreader.hpp>
-
-#include "esm/esmfile.hpp"
-
-#include "datafilesmodel.hpp"
-
-#include <QDebug>
-
-DataFilesModel::DataFilesModel(QObject *parent) :
- QAbstractTableModel(parent)
-{
- mEncoding = QString("win1252");
-}
-
-DataFilesModel::~DataFilesModel()
-{
-}
-
-void DataFilesModel::setEncoding(const QString &encoding)
-{
- mEncoding = encoding;
-}
-
-void DataFilesModel::setCheckState(const QModelIndex &index, Qt::CheckState state)
-{
- setData(index, state, Qt::CheckStateRole);
-}
-
-Qt::CheckState DataFilesModel::checkState(const QModelIndex &index)
-{
- EsmFile *file = item(index.row());
- return mCheckStates[file->fileName()];
-}
-
-int DataFilesModel::columnCount(const QModelIndex &parent) const
-{
- return parent.isValid() ? 0 : 9;
-}
-
-int DataFilesModel::rowCount(const QModelIndex &parent) const
-{
- return parent.isValid() ? 0 : mFiles.count();
-}
-
-
-bool DataFilesModel::moveRow(int oldrow, int row, const QModelIndex &parent)
-{
- if (oldrow < 0 || row < 0 || oldrow == row)
- return false;
-
- emit layoutAboutToBeChanged();
- //emit beginMoveRows(parent, oldrow, oldrow, parent, row);
- mFiles.swap(oldrow, row);
- //emit endInsertRows();
- emit layoutChanged();
-
- return true;
-}
-
-QVariant DataFilesModel::data(const QModelIndex &index, int role) const
-{
- if (!index.isValid())
- return QVariant();
-
- EsmFile *file = item(index.row());
-
- if (!file)
- return QVariant();
-
- const int column = index.column();
-
- switch (role) {
- case Qt::DisplayRole: {
-
- switch (column) {
- case 0:
- return file->fileName();
- case 1:
- return file->author();
- case 2:
- return QString("%1 kB").arg(int((file->size() + 1023) / 1024));
- case 3:
- //return file->modified().toString(Qt::TextDate);
- return file->modified().toString(Qt::ISODate);
- case 4:
- return file->accessed().toString(Qt::TextDate);
- case 5:
- return file->version();
- case 6:
- return file->path();
- case 7:
- return file->masters().join(", ");
- case 8:
- return file->description();
- }
- }
-
- case Qt::TextAlignmentRole: {
- switch (column) {
- case 0:
- case 1:
- return Qt::AlignLeft + Qt::AlignVCenter;
- case 2:
- case 3:
- case 4:
- case 5:
- return Qt::AlignRight + Qt::AlignVCenter;
- default:
- return Qt::AlignLeft + Qt::AlignVCenter;
- }
- }
-
- case Qt::CheckStateRole: {
- if (column != 0)
- return QVariant();
- return mCheckStates[file->fileName()];
- }
- case Qt::ToolTipRole:
- {
- if (column != 0)
- return QVariant();
-
- if (file->version() == 0.0f)
- return QVariant(); // Data not set
-
- QString tooltip =
- QString("<b>Author:</b> %1<br/> \
- <b>Version:</b> %2<br/> \
- <br/><b>Description:</b><br/>%3<br/> \
- <br/><b>Dependencies: </b>%4<br/>")
- .arg(file->author())
- .arg(QString::number(file->version()))
- .arg(file->description())
- .arg(file->masters().join(", "));
-
-
- return tooltip;
-
- }
- default:
- return QVariant();
- }
-
-}
-
-Qt::ItemFlags DataFilesModel::flags(const QModelIndex &index) const
-{
- if (!index.isValid())
- return Qt::NoItemFlags;
-
- EsmFile *file = item(index.row());
-
- if (!file)
- return Qt::NoItemFlags;
-
- if (canBeChecked(file)) {
- if (index.column() == 0) {
- return Qt::ItemIsUserCheckable | Qt::ItemIsEnabled | Qt::ItemIsSelectable;
- } else {
- return Qt::ItemIsEnabled | Qt::ItemIsSelectable;
- }
- } else {
- if (index.column() == 0) {
- return Qt::ItemIsUserCheckable | Qt::ItemIsSelectable;
- } else {
- return Qt::NoItemFlags | Qt::ItemIsSelectable;
- }
- }
-
-}
-
-QVariant DataFilesModel::headerData(int section, Qt::Orientation orientation, int role) const
-{
- if (role != Qt::DisplayRole)
- return QVariant();
-
- if (orientation == Qt::Horizontal) {
- switch (section) {
- case 0: return tr("Name");
- case 1: return tr("Author");
- case 2: return tr("Size");
- case 3: return tr("Modified");
- case 4: return tr("Accessed");
- case 5: return tr("Version");
- case 6: return tr("Path");
- case 7: return tr("Masters");
- case 8: return tr("Description");
- }
- } else {
- // Show row numbers
- return ++section;
- }
-
- return QVariant();
-}
-
-bool DataFilesModel::setData(const QModelIndex &index, const QVariant &value, int role)
-{
- if (!index.isValid())
- return false;
-
- if (role == Qt::CheckStateRole) {
- QString name = item(index.row())->fileName();
- mCheckStates[name] = static_cast<Qt::CheckState>(value.toInt());
-
- // Force a redraw of the view since unchecking one item can affect another
- QModelIndex firstIndex = indexFromItem(mFiles.first());
- QModelIndex lastIndex = indexFromItem(mFiles.last());
-
- emit dataChanged(firstIndex, lastIndex);
- emit checkedItemsChanged(checkedItems());
- return true;
- }
-
- return false;
-}
-
-bool lessThanEsmFile(const EsmFile *e1, const EsmFile *e2)
-{
- //Masters first then alphabetically
- if (e1->fileName().endsWith(".esm") && !e2->fileName().endsWith(".esm"))
- return true;
- if (!e1->fileName().endsWith(".esm") && e2->fileName().endsWith(".esm"))
- return false;
-
- return e1->fileName().toLower() < e2->fileName().toLower();
-}
-
-bool lessThanDate(const EsmFile *e1, const EsmFile *e2)
-{
- if (e1->modified().toString(Qt::ISODate) < e2->modified().toString(Qt::ISODate)) {
- return true;
- } else {
- return false;
- }
-}
-
-void DataFilesModel::sort(int column, Qt::SortOrder order)
-{
- emit layoutAboutToBeChanged();
-
- if (column == 3) {
- qSort(mFiles.begin(), mFiles.end(), lessThanDate);
- } else {
- qSort(mFiles.begin(), mFiles.end(), lessThanEsmFile);
- }
-
- emit layoutChanged();
-}
-
-void DataFilesModel::addFile(EsmFile *file)
-{
- emit beginInsertRows(QModelIndex(), mFiles.count(), mFiles.count());
- mFiles.append(file);
- emit endInsertRows();
-}
-
-void DataFilesModel::addFiles(const QString &path)
-{
- QDir dir(path);
- QStringList filters;
- filters << "*.esp" << "*.esm";
- dir.setNameFilters(filters);
-
- // Create a decoder for non-latin characters in esx metadata
- QTextCodec *codec;
-
- if (mEncoding == QLatin1String("win1252")) {
- codec = QTextCodec::codecForName("windows-1252");
- } else if (mEncoding == QLatin1String("win1251")) {
- codec = QTextCodec::codecForName("windows-1251");
- } else if (mEncoding == QLatin1String("win1250")) {
- codec = QTextCodec::codecForName("windows-1250");
- } else {
- return; // This should never happen;
- }
-
- QTextDecoder *decoder = codec->makeDecoder();
-
- foreach (const QString &path, dir.entryList()) {
- QFileInfo info(dir.absoluteFilePath(path));
- EsmFile *file = new EsmFile(path);
-
- try {
- ESM::ESMReader fileReader;
- ToUTF8::Utf8Encoder encoder(ToUTF8::calculateEncoding(mEncoding.toStdString()));
- fileReader.setEncoder(&encoder);
- fileReader.open(dir.absoluteFilePath(path).toStdString());
-
- std::vector<ESM::Header::MasterData> mlist = fileReader.getMasters();
-
- QStringList masters;
-
- for (unsigned int i = 0; i < mlist.size(); ++i) {
- QString master = QString::fromStdString(mlist[i].name);
- masters.append(master);
- }
-
- file->setAuthor(decoder->toUnicode(fileReader.getAuthor().c_str()));
- file->setSize(info.size());
- file->setDates(info.lastModified(), info.lastRead());
- file->setVersion(fileReader.getFVer());
- file->setPath(info.absoluteFilePath());
- file->setMasters(masters);
- file->setDescription(decoder->toUnicode(fileReader.getDesc().c_str()));
-
-
- // Put the file in the table
- if (findItem(path) == 0)
- addFile(file);
- } catch(std::runtime_error &e) {
- // An error occurred while reading the .esp
- qWarning() << "Error reading esp: " << e.what();
- continue;
- }
-
- }
-
- delete decoder;
-}
-
-QModelIndex DataFilesModel::indexFromItem(EsmFile *item) const
-{
- if (item)
- return createIndex(mFiles.indexOf(item), 0);
-
- return QModelIndex();
-}
-
-EsmFile* DataFilesModel::findItem(const QString &name)
-{
- QList<EsmFile *>::ConstIterator it;
- QList<EsmFile *>::ConstIterator itEnd = mFiles.constEnd();
-
- int i = 0;
- for (it = mFiles.constBegin(); it != itEnd; ++it) {
- EsmFile *file = item(i);
- ++i;
-
- if (name == file->fileName())
- return file;
- }
-
- // Not found
- return 0;
-}
-
-EsmFile* DataFilesModel::item(int row) const
-{
- if (row >= 0 && row < mFiles.count())
- return mFiles.at(row);
- else
- return 0;
-}
-
-QStringList DataFilesModel::checkedItems()
-{
- QStringList list;
-
- QList<EsmFile *>::ConstIterator it;
- QList<EsmFile *>::ConstIterator itEnd = mFiles.constEnd();
-
- int i = 0;
- for (it = mFiles.constBegin(); it != itEnd; ++it) {
- EsmFile *file = item(i);
- ++i;
-
- QString name = file->fileName();
-
- // Only add the items that are in the checked list and available
- if (mCheckStates[name] == Qt::Checked && canBeChecked(file))
- list << name;
- }
-
- return list;
-}
-
-QStringList DataFilesModel::checkedItemsPaths()
-{
- QStringList list;
-
- QList<EsmFile *>::ConstIterator it;
- QList<EsmFile *>::ConstIterator itEnd = mFiles.constEnd();
-
- int i = 0;
- for (it = mFiles.constBegin(); it != itEnd; ++it) {
- EsmFile *file = item(i);
- ++i;
-
- if (mCheckStates[file->fileName()] == Qt::Checked && canBeChecked(file))
- list << file->path();
- }
-
- return list;
-}
-
-void DataFilesModel::uncheckAll()
-{
- emit layoutAboutToBeChanged();
- mCheckStates.clear();
- emit layoutChanged();
-}
-
-QStringList DataFilesModel::uncheckedItems()
-{
- QStringList list;
- QStringList checked = checkedItems();
-
- QList<EsmFile *>::ConstIterator it;
- QList<EsmFile *>::ConstIterator itEnd = mFiles.constEnd();
-
- int i = 0;
- for (it = mFiles.constBegin(); it != itEnd; ++it) {
- EsmFile *file = item(i);
- ++i;
-
- // Add the items that are not in the checked list
- if (!checked.contains(file->fileName()))
- list << file->fileName();
- }
-
- return list;
-}
-
-bool DataFilesModel::canBeChecked(EsmFile *file) const
-{
- //element can be checked if all its dependencies are
- bool canBeChecked = true;
- foreach (const QString &master, file->masters())
- {
- if (!mCheckStates.contains(master) || mCheckStates[master] != Qt::Checked)
- {
- canBeChecked = false;
- break;
- }
- }
- return canBeChecked;
-}
diff --git a/components/fileorderlist/model/datafilesmodel.hpp b/components/fileorderlist/model/datafilesmodel.hpp
deleted file mode 100644
index 0a07a536f8..0000000000
--- a/components/fileorderlist/model/datafilesmodel.hpp
+++ /dev/null
@@ -1,66 +0,0 @@
-#ifndef DATAFILESMODEL_HPP
-#define DATAFILESMODEL_HPP
-
-#include <QAbstractTableModel>
-#include <QStringList>
-#include <QString>
-#include <QHash>
-
-
-class EsmFile;
-
-class DataFilesModel : public QAbstractTableModel
-{
- Q_OBJECT
-
-public:
- explicit DataFilesModel(QObject *parent = 0);
- virtual ~DataFilesModel();
- virtual int columnCount(const QModelIndex &parent = QModelIndex()) const;
- virtual int rowCount(const QModelIndex &parent = QModelIndex()) const;
-
- bool moveRow(int oldrow, int row, const QModelIndex &parent = QModelIndex());
-
- virtual Qt::ItemFlags flags(const QModelIndex &index) const;
-
- virtual QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const;
- virtual QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const;
-
- virtual bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole);
- void sort(int column, Qt::SortOrder order = Qt::AscendingOrder);
-
- inline QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const
- { return QAbstractTableModel::index(row, column, parent); }
-
- void setEncoding(const QString &encoding);
-
- void addFiles(const QString &path);
-
- void uncheckAll();
-
- QStringList checkedItems();
- QStringList uncheckedItems();
- QStringList checkedItemsPaths();
-
- Qt::CheckState checkState(const QModelIndex &index);
- void setCheckState(const QModelIndex &index, Qt::CheckState state);
-
- QModelIndex indexFromItem(EsmFile *item) const;
- EsmFile* findItem(const QString &name);
- EsmFile* item(int row) const;
-
-signals:
- void checkedItemsChanged(const QStringList &items);
-
-private:
- bool canBeChecked(EsmFile *file) const;
- void addFile(EsmFile *file);
-
- QList<EsmFile *> mFiles;
- QHash<QString, Qt::CheckState> mCheckStates;
-
- QString mEncoding;
-
-};
-
-#endif // DATAFILESMODEL_HPP
diff --git a/components/fileorderlist/model/esm/esmfile.cpp b/components/fileorderlist/model/esm/esmfile.cpp
deleted file mode 100644
index 93d83091e7..0000000000
--- a/components/fileorderlist/model/esm/esmfile.cpp
+++ /dev/null
@@ -1,50 +0,0 @@
-#include "esmfile.hpp"
-
-EsmFile::EsmFile(QString fileName, ModelItem *parent)
- : ModelItem(parent)
-{
- mFileName = fileName;
- mSize = 0;
- mVersion = 0.0f;
-}
-
-void EsmFile::setFileName(const QString &fileName)
-{
- mFileName = fileName;
-}
-
-void EsmFile::setAuthor(const QString &author)
-{
- mAuthor = author;
-}
-
-void EsmFile::setSize(const int size)
-{
- mSize = size;
-}
-
-void EsmFile::setDates(const QDateTime &modified, const QDateTime &accessed)
-{
- mModified = modified;
- mAccessed = accessed;
-}
-
-void EsmFile::setVersion(float version)
-{
- mVersion = version;
-}
-
-void EsmFile::setPath(const QString &path)
-{
- mPath = path;
-}
-
-void EsmFile::setMasters(const QStringList &masters)
-{
- mMasters = masters;
-}
-
-void EsmFile::setDescription(const QString &description)
-{
- mDescription = description;
-}
diff --git a/components/fileorderlist/model/esm/esmfile.hpp b/components/fileorderlist/model/esm/esmfile.hpp
deleted file mode 100644
index 52b3fbd007..0000000000
--- a/components/fileorderlist/model/esm/esmfile.hpp
+++ /dev/null
@@ -1,54 +0,0 @@
-#ifndef ESMFILE_HPP
-#define ESMFILE_HPP
-
-#include <QDateTime>
-#include <QStringList>
-
-#include "../modelitem.hpp"
-
-class EsmFile : public ModelItem
-{
- Q_OBJECT
- Q_PROPERTY(QString filename READ fileName)
-
-public:
- EsmFile(QString fileName = QString(), ModelItem *parent = 0);
-
- ~EsmFile()
- {}
-
- void setFileName(const QString &fileName);
- void setAuthor(const QString &author);
- void setSize(const int size);
- void setDates(const QDateTime &modified, const QDateTime &accessed);
- void setVersion(const float version);
- void setPath(const QString &path);
- void setMasters(const QStringList &masters);
- void setDescription(const QString &description);
-
- inline QString fileName() const { return mFileName; }
- inline QString author() const { return mAuthor; }
- inline int size() const { return mSize; }
- inline QDateTime modified() const { return mModified; }
- inline QDateTime accessed() const { return mAccessed; }
- inline float version() const { return mVersion; }
- inline QString path() const { return mPath; }
- inline QStringList masters() const { return mMasters; }
- inline QString description() const { return mDescription; }
-
-
-private:
- QString mFileName;
- QString mAuthor;
- int mSize;
- QDateTime mModified;
- QDateTime mAccessed;
- float mVersion;
- QString mPath;
- QStringList mMasters;
- QString mDescription;
-
-};
-
-
-#endif
diff --git a/components/fileorderlist/model/modelitem.cpp b/components/fileorderlist/model/modelitem.cpp
deleted file mode 100644
index 0ff7e45cb9..0000000000
--- a/components/fileorderlist/model/modelitem.cpp
+++ /dev/null
@@ -1,57 +0,0 @@
-#include "modelitem.hpp"
-
-ModelItem::ModelItem(ModelItem *parent)
- : mParentItem(parent)
- , QObject(parent)
-{
-}
-
-ModelItem::~ModelItem()
-{
- qDeleteAll(mChildItems);
-}
-
-
-ModelItem *ModelItem::parent()
-{
- return mParentItem;
-}
-
-int ModelItem::row() const
-{
- if (mParentItem)
- return 1;
- //return mParentItem->childRow(const_cast<ModelItem*>(this));
- //return mParentItem->mChildItems.indexOf(const_cast<ModelItem*>(this));
-
- return -1;
-}
-
-
-int ModelItem::childCount() const
-{
- return mChildItems.count();
-}
-
-int ModelItem::childRow(ModelItem *child) const
-{
- Q_ASSERT(child);
-
- return mChildItems.indexOf(child);
-}
-
-ModelItem *ModelItem::child(int row)
-{
- return mChildItems.value(row);
-}
-
-
-void ModelItem::appendChild(ModelItem *item)
-{
- mChildItems.append(item);
-}
-
-void ModelItem::removeChild(int row)
-{
- mChildItems.removeAt(row);
-}
diff --git a/components/fileorderlist/model/modelitem.hpp b/components/fileorderlist/model/modelitem.hpp
deleted file mode 100644
index f4cb4322ff..0000000000
--- a/components/fileorderlist/model/modelitem.hpp
+++ /dev/null
@@ -1,32 +0,0 @@
-#ifndef MODELITEM_HPP
-#define MODELITEM_HPP
-
-#include <QObject>
-#include <QList>
-
-class ModelItem : public QObject
-{
- Q_OBJECT
-
-public:
- ModelItem(ModelItem *parent = 0);
- ~ModelItem();
-
- ModelItem *parent();
- int row() const;
-
- int childCount() const;
- int childRow(ModelItem *child) const;
- ModelItem *child(int row);
-
- void appendChild(ModelItem *child);
- void removeChild(int row);
-
- //virtual bool acceptChild(ModelItem *child);
-
-protected:
- ModelItem *mParentItem;
- QList<ModelItem*> mChildItems;
-};
-
-#endif
diff --git a/components/fileorderlist/model/pluginsproxymodel.cpp b/components/fileorderlist/model/pluginsproxymodel.cpp
deleted file mode 100644
index 6be152b555..0000000000
--- a/components/fileorderlist/model/pluginsproxymodel.cpp
+++ /dev/null
@@ -1,17 +0,0 @@
-#include "pluginsproxymodel.hpp"
-
-PluginsProxyModel::PluginsProxyModel(QObject *parent) :
- QSortFilterProxyModel(parent)
-{
-}
-
-PluginsProxyModel::~PluginsProxyModel()
-{
-}
-
-QVariant PluginsProxyModel::headerData(int section, Qt::Orientation orientation, int role) const
-{
- if (orientation != Qt::Vertical || role != Qt::DisplayRole)
- return QSortFilterProxyModel::headerData(section, orientation, role);
- return section + 1;
-}
diff --git a/components/fileorderlist/model/pluginsproxymodel.hpp b/components/fileorderlist/model/pluginsproxymodel.hpp
deleted file mode 100644
index 8fde732361..0000000000
--- a/components/fileorderlist/model/pluginsproxymodel.hpp
+++ /dev/null
@@ -1,18 +0,0 @@
-#ifndef PLUGINSPROXYMODEL_HPP
-#define PLUGINSPROXYMODEL_HPP
-
-#include <QSortFilterProxyModel>
-
-class QVariant;
-
-class PluginsProxyModel : public QSortFilterProxyModel
-{
- Q_OBJECT
-public:
- explicit PluginsProxyModel(QObject *parent = 0);
- ~PluginsProxyModel();
-
- QVariant headerData(int section, Qt::Orientation orientation, int role) const;
-};
-
-#endif // PLUGINSPROXYMODEL_HPP
diff --git a/components/fileorderlist/utils/comboboxlineedit.cpp b/components/fileorderlist/utils/comboboxlineedit.cpp
deleted file mode 100644
index 4d62e1399a..0000000000
--- a/components/fileorderlist/utils/comboboxlineedit.cpp
+++ /dev/null
@@ -1,35 +0,0 @@
-#include <QToolButton>
-#include <QStyle>
-
-#include "comboboxlineedit.hpp"
-
-ComboBoxLineEdit::ComboBoxLineEdit(QWidget *parent)
- : QLineEdit(parent)
-{
- mClearButton = new QToolButton(this);
- QPixmap pixmap(":images/clear.png");
- mClearButton->setIcon(QIcon(pixmap));
- mClearButton->setIconSize(pixmap.size());
- mClearButton->setCursor(Qt::ArrowCursor);
- mClearButton->setStyleSheet("QToolButton { border: none; padding: 0px; }");
- mClearButton->hide();
- connect(mClearButton, SIGNAL(clicked()), this, SLOT(clear()));
- connect(this, SIGNAL(textChanged(const QString&)), this, SLOT(updateClearButton(const QString&)));
- int frameWidth = style()->pixelMetric(QStyle::PM_DefaultFrameWidth);
-
- setObjectName(QString("ComboBoxLineEdit"));
- setStyleSheet(QString("ComboBoxLineEdit { background-color: transparent; padding-right: %1px; } ").arg(mClearButton->sizeHint().width() + frameWidth + 1));
-}
-
-void ComboBoxLineEdit::resizeEvent(QResizeEvent *)
-{
- QSize sz = mClearButton->sizeHint();
- int frameWidth = style()->pixelMetric(QStyle::PM_DefaultFrameWidth);
- mClearButton->move(rect().right() - frameWidth - sz.width(),
- (rect().bottom() + 1 - sz.height())/2);
-}
-
-void ComboBoxLineEdit::updateClearButton(const QString& text)
-{
- mClearButton->setVisible(!text.isEmpty());
-}
diff --git a/components/fileorderlist/utils/comboboxlineedit.hpp b/components/fileorderlist/utils/comboboxlineedit.hpp
deleted file mode 100644
index ba10731ae3..0000000000
--- a/components/fileorderlist/utils/comboboxlineedit.hpp
+++ /dev/null
@@ -1,35 +0,0 @@
-/****************************************************************************
-**
-** Copyright (c) 2007 Trolltech ASA <info@trolltech.com>
-**
-** Use, modification and distribution is allowed without limitation,
-** warranty, liability or support of any kind.
-**
-****************************************************************************/
-
-#ifndef LINEEDIT_H
-#define LINEEDIT_H
-
-#include <QLineEdit>
-
-class QToolButton;
-
-class ComboBoxLineEdit : public QLineEdit
-{
- Q_OBJECT
-
-public:
- ComboBoxLineEdit(QWidget *parent = 0);
-
-protected:
- void resizeEvent(QResizeEvent *);
-
-private slots:
- void updateClearButton(const QString &text);
-
-private:
- QToolButton *mClearButton;
-};
-
-#endif // LIENEDIT_H
-
diff --git a/components/fileorderlist/utils/naturalsort.hpp b/components/fileorderlist/utils/naturalsort.hpp
deleted file mode 100644
index 59271547a5..0000000000
--- a/components/fileorderlist/utils/naturalsort.hpp
+++ /dev/null
@@ -1,11 +0,0 @@
-#ifndef NATURALSORT_H
-#define NATURALSORT_H
-
-#include <QString>
-
-bool naturalSortLessThanCS( const QString &left, const QString &right );
-bool naturalSortLessThanCI( const QString &left, const QString &right );
-bool naturalSortGreaterThanCS( const QString &left, const QString &right );
-bool naturalSortGreaterThanCI( const QString &left, const QString &right );
-
-#endif
diff --git a/components/fileorderlist/utils/profilescombobox.hpp b/components/fileorderlist/utils/profilescombobox.hpp
deleted file mode 100644
index 08ead9a7ab..0000000000
--- a/components/fileorderlist/utils/profilescombobox.hpp
+++ /dev/null
@@ -1,30 +0,0 @@
-#ifndef PROFILESCOMBOBOX_HPP
-#define PROFILESCOMBOBOX_HPP
-
-#include <QComboBox>
-
-class QString;
-class QRegExpValidator;
-
-class ProfilesComboBox : public QComboBox
-{
- Q_OBJECT
-public:
- explicit ProfilesComboBox(QWidget *parent = 0);
- void setEditEnabled(bool editable);
-
-signals:
- void profileChanged(const QString &previous, const QString &current);
- void profileRenamed(const QString &oldName, const QString &newName);
-
-private slots:
- void slotEditingFinished();
- void slotIndexChanged(int index);
- void slotTextChanged(const QString &text);
-
-private:
- QString mOldProfile;
- QRegExpValidator *mValidator;
-};
-
-#endif // PROFILESCOMBOBOX_HPP
diff --git a/components/files/configurationmanager.cpp b/components/files/configurationmanager.cpp
index 56e55a98d1..75c877dc5d 100644
--- a/components/files/configurationmanager.cpp
+++ b/components/files/configurationmanager.cpp
@@ -56,7 +56,7 @@ void ConfigurationManager::readConfiguration(boost::program_options::variables_m
}
-void ConfigurationManager::processPaths(Files::PathContainer& dataDirs)
+void ConfigurationManager::processPaths(Files::PathContainer& dataDirs, bool create)
{
std::string path;
for (Files::PathContainer::iterator it = dataDirs.begin(); it != dataDirs.end(); ++it)
@@ -94,6 +94,18 @@ void ConfigurationManager::processPaths(Files::PathContainer& dataDirs)
if (!boost::filesystem::is_directory(*it))
{
+ if (create)
+ {
+ try
+ {
+ boost::filesystem::create_directories (*it);
+ }
+ catch (...) {}
+
+ if (boost::filesystem::is_directory(*it))
+ continue;
+ }
+
(*it).clear();
}
}
diff --git a/components/files/configurationmanager.hpp b/components/files/configurationmanager.hpp
index 765f1cebf8..4df8716647 100644
--- a/components/files/configurationmanager.hpp
+++ b/components/files/configurationmanager.hpp
@@ -30,7 +30,9 @@ struct ConfigurationManager
void readConfiguration(boost::program_options::variables_map& variables,
boost::program_options::options_description& description);
- void processPaths(Files::PathContainer& dataDirs);
+
+ void processPaths(Files::PathContainer& dataDirs, bool create = false);
+ ///< \param create Try creating the directory, if it does not exist.
/**< Fixed paths */
const boost::filesystem::path& getGlobalPath() const;
diff --git a/components/misc/tests/.gitignore b/components/misc/tests/.gitignore
new file mode 100644
index 0000000000..8144904045
--- /dev/null
+++ b/components/misc/tests/.gitignore
@@ -0,0 +1 @@
+*_test
diff --git a/components/nif/.gitignore b/components/nif/.gitignore
new file mode 100644
index 0000000000..731498d9a1
--- /dev/null
+++ b/components/nif/.gitignore
@@ -0,0 +1 @@
+old_d
diff --git a/components/nif/niffile.cpp b/components/nif/niffile.cpp
index cb7c2feb07..402eadefb4 100644
--- a/components/nif/niffile.cpp
+++ b/components/nif/niffile.cpp
@@ -425,7 +425,7 @@ void Node::getProperties(const Nif::NiTexturingProperty *&texprop,
Ogre::Matrix4 Node::getLocalTransform() const
{
- Ogre::Matrix4 mat4(Ogre::Matrix4::IDENTITY);
+ Ogre::Matrix4 mat4 = Ogre::Matrix4(Ogre::Matrix4::IDENTITY);
mat4.makeTransform(trafo.pos, Ogre::Vector3(trafo.scale), Ogre::Quaternion(trafo.rotation));
return mat4;
}
diff --git a/components/nif/tests/.gitignore b/components/nif/tests/.gitignore
new file mode 100644
index 0000000000..b01c11f272
--- /dev/null
+++ b/components/nif/tests/.gitignore
@@ -0,0 +1,5 @@
+niftool
+*_test
+*.nif
+*.kf
+output.txt
diff --git a/components/nifogre/tests/.gitignore b/components/nifogre/tests/.gitignore
new file mode 100644
index 0000000000..1a55699834
--- /dev/null
+++ b/components/nifogre/tests/.gitignore
@@ -0,0 +1,5 @@
+*.png
+meshlist.txt
+ogre.cfg
+*_test
+chris*
diff --git a/components/to_utf8/.gitignore b/components/to_utf8/.gitignore
new file mode 100644
index 0000000000..4e0357749e
--- /dev/null
+++ b/components/to_utf8/.gitignore
@@ -0,0 +1 @@
+gen_iconv
diff --git a/components/to_utf8/tests/.gitignore b/components/to_utf8/tests/.gitignore
new file mode 100644
index 0000000000..8144904045
--- /dev/null
+++ b/components/to_utf8/tests/.gitignore
@@ -0,0 +1 @@
+*_test
diff --git a/credits.txt b/credits.txt
index 9a84c5327d..bd0c6ca743 100644
--- a/credits.txt
+++ b/credits.txt
@@ -12,6 +12,7 @@ Marc Zinnschlag (Zini) - Lead Programmer/Project Manager
Adam Hogan (aurix)
Aleksandar Jovanov
+Alex Haddad (rainChu)
Alex McKibben (WeirdSexy)
Alexander Nadeau (wareya)
Alexander Olofsson (Ace)
@@ -47,6 +48,7 @@ Marc Bouvier (CramitDeFrog)
Marcin Hulist (Gohan)
Mark Siewert (mark76)
Mateusz Kołaczek (PL_kolek)
+Michael Hogan (Xethik)
Michael Mc Donnell
Michael Papageorgiou (werdanith)
Michał Bień (Glorf)
@@ -61,6 +63,7 @@ Roman Proskuryakov (humbug)
Sandy Carter (bwrsandman)
Sebastian Wick (swick)
Sergey Shambir
+sir_herrbatka
Sylvain Thesnieres (Garvek)
Tom Mason (wheybags)
Torben Leif Carrington (TorbenC)
diff --git a/extern/oics/CMakeLists.txt b/extern/oics/CMakeLists.txt
index 7c14387a4b..5c1edbf62b 100644
--- a/extern/oics/CMakeLists.txt
+++ b/extern/oics/CMakeLists.txt
@@ -9,12 +9,23 @@ set(OICS_SOURCE_FILES
ICSInputControlSystem_keyboard.cpp
ICSInputControlSystem_mouse.cpp
ICSInputControlSystem_joystick.cpp
+)
+
+set(TINYXML_SOURCE_FILES
tinyxml.cpp
tinyxmlparser.cpp
tinyxmlerror.cpp
- tinystr.cpp
+ tinystr.cpp
)
-add_library(${OICS_LIBRARY} STATIC ${OICS_SOURCE_FILES})
+if(USE_SYSTEM_TINYXML)
+ add_library(${OICS_LIBRARY} STATIC ${OICS_SOURCE_FILES})
+ target_link_libraries(${OICS_LIBRARY} ${TINYXML_LIBRARIES})
+else()
+ add_library(${OICS_LIBRARY} STATIC
+ ${OICS_SOURCE_FILES}
+ ${TINYXML_SOURCE_FILES})
+endif()
+# Does this do anything?
link_directories(${CMAKE_CURRENT_BINARY_DIR})
diff --git a/extern/sdl4ogre/sdlinputwrapper.cpp b/extern/sdl4ogre/sdlinputwrapper.cpp
index 931d6aca30..df74bba3b6 100644
--- a/extern/sdl4ogre/sdlinputwrapper.cpp
+++ b/extern/sdl4ogre/sdlinputwrapper.cpp
@@ -30,9 +30,6 @@ namespace SFO
InputWrapper::~InputWrapper()
{
- if(mSDLWindow != NULL)
- SDL_DestroyWindow(mSDLWindow);
- mSDLWindow = NULL;
}
void InputWrapper::capture(bool windowEventsOnly)
diff --git a/files/mac/opencs.icns b/files/mac/opencs.icns
new file mode 100644
index 0000000000..98812f871d
--- /dev/null
+++ b/files/mac/opencs.icns
Binary files differ
diff --git a/files/mygui/CMakeLists.txt b/files/mygui/CMakeLists.txt
index 1ec1e08cb5..21153a4740 100644
--- a/files/mygui/CMakeLists.txt
+++ b/files/mygui/CMakeLists.txt
@@ -9,7 +9,6 @@ set(MYGUI_FILES
core.skin
core.xml
EBGaramond-Regular.ttf
- Obliviontt.zip
openmw_alchemy_window.layout
openmw_book.layout
openmw_box.skin.xml
diff --git a/files/mygui/Obliviontt.zip b/files/mygui/Obliviontt.zip
deleted file mode 100644
index af4f809fd8..0000000000
--- a/files/mygui/Obliviontt.zip
+++ /dev/null
Binary files differ
diff --git a/files/mygui/openmw_console.layout b/files/mygui/openmw_console.layout
index bfda40c68b..7d24a283e1 100644
--- a/files/mygui/openmw_console.layout
+++ b/files/mygui/openmw_console.layout
@@ -9,6 +9,7 @@
<!-- Log window -->
<Widget type="EditBox" skin="MW_ConsoleLog" position="5 5 380 328" align="Stretch" name="list_History">
<Property key="MultiLine" value="1"/>
+ <Property key="ReadOnly" value="true"/>
</Widget>
<!-- Command line -->
diff --git a/files/mygui/openmw_hud.layout b/files/mygui/openmw_hud.layout
index e39777dd0f..72d337e45d 100644
--- a/files/mygui/openmw_hud.layout
+++ b/files/mygui/openmw_hud.layout
@@ -45,6 +45,7 @@
<Widget type="ProgressBar" skin="MW_Progress_Loading" position="12 36 196 8" align="Center Top" name="Drowning">
<Property key="NeedMouse" value="false"/>
</Widget>
+ <Widget type="Widget" skin="MW_Progress_Drowning" position="14 38 192 4" align="Center Top" name="Flash"/>
</Widget>
<!-- Equipped weapon/selected spell name display for a few seconds after it changes -->
diff --git a/files/mygui/openmw_progress.skin.xml b/files/mygui/openmw_progress.skin.xml
index 35114ffebb..f5418e3f88 100644
--- a/files/mygui/openmw_progress.skin.xml
+++ b/files/mygui/openmw_progress.skin.xml
@@ -17,6 +17,11 @@
<State name="normal" offset="0 28 2 14"/>
</BasisSkin>
</Skin>
+ <Skin name="MW_BigTrack_Progress_Red_Small" size="2 6" texture="smallbars.png" >
+ <BasisSkin type="MainSkin" offset="0 0 2 6" align="Stretch">
+ <State name="normal" offset="0 0 2 8"/>
+ </BasisSkin>
+ </Skin>
<Skin name="MW_BigTrack_Progress_Blue_Small" size="2 6" texture="smallbars.png" >
<BasisSkin type="MainSkin" offset="0 0 2 6" align="Stretch">
<State name="normal" offset="0 26 2 6"/>
@@ -65,6 +70,10 @@
<Child type="Widget" skin="BlackBG" offset="2 2 60 2" align="Stretch" name="Client"/>
</Skin>
+ <Skin name="MW_Progress_Drowning" size="64 6">
+ <Child type="Widget" skin="MW_BigTrack_Progress_Red_Small" offset="0 0 64 6" align="Stretch"/>
+ </Skin>
+
<Skin name="MW_ProgressScroll_Loading" size="64 6">
<Property key="TrackWidth" value="1"/>
<Property key="TrackRangeMargins" value="0 0"/>
diff --git a/files/opencs/GMST.png b/files/opencs/GMST.png
new file mode 100644
index 0000000000..f246202882
--- /dev/null
+++ b/files/opencs/GMST.png
Binary files differ
diff --git a/files/opencs/Info.png b/files/opencs/Info.png
new file mode 100644
index 0000000000..d7bdad6cb1
--- /dev/null
+++ b/files/opencs/Info.png
Binary files differ
diff --git a/files/opencs/LandTexture.png b/files/opencs/LandTexture.png
new file mode 100644
index 0000000000..84f7290981
--- /dev/null
+++ b/files/opencs/LandTexture.png
Binary files differ
diff --git a/files/opencs/PathGrid.png b/files/opencs/PathGrid.png
new file mode 100644
index 0000000000..23b6b84d74
--- /dev/null
+++ b/files/opencs/PathGrid.png
Binary files differ
diff --git a/files/opencs/activator.png b/files/opencs/activator.png
index 0446af22cf..32cc6f8a3c 100755..100644
--- a/files/opencs/activator.png
+++ b/files/opencs/activator.png
Binary files differ
diff --git a/files/opencs/added.png b/files/opencs/added.png
index aff7e25d46..ddd9c2108e 100644
--- a/files/opencs/added.png
+++ b/files/opencs/added.png
Binary files differ
diff --git a/files/opencs/apparatus.png b/files/opencs/apparatus.png
index 3cef537e14..3cef537e14 100755..100644
--- a/files/opencs/apparatus.png
+++ b/files/opencs/apparatus.png
Binary files differ
diff --git a/files/opencs/armor.png b/files/opencs/armor.png
index fc534c7d1c..fc534c7d1c 100755..100644
--- a/files/opencs/armor.png
+++ b/files/opencs/armor.png
Binary files differ
diff --git a/files/opencs/attribute.png b/files/opencs/attribute.png
new file mode 100644
index 0000000000..4aa5dc02e5
--- /dev/null
+++ b/files/opencs/attribute.png
Binary files differ
diff --git a/files/opencs/birthsign.png b/files/opencs/birthsign.png
new file mode 100644
index 0000000000..8192d2ebf8
--- /dev/null
+++ b/files/opencs/birthsign.png
Binary files differ
diff --git a/files/opencs/body-part.png b/files/opencs/body-part.png
new file mode 100644
index 0000000000..823e437126
--- /dev/null
+++ b/files/opencs/body-part.png
Binary files differ
diff --git a/files/opencs/book.png b/files/opencs/book.png
index 3afa9e8aae..9d7669bd7e 100755..100644
--- a/files/opencs/book.png
+++ b/files/opencs/book.png
Binary files differ
diff --git a/files/opencs/cell.png b/files/opencs/cell.png
new file mode 100644
index 0000000000..c4f00c1f07
--- /dev/null
+++ b/files/opencs/cell.png
Binary files differ
diff --git a/files/opencs/class.png b/files/opencs/class.png
new file mode 100644
index 0000000000..316380363a
--- /dev/null
+++ b/files/opencs/class.png
Binary files differ
diff --git a/files/opencs/clothing.png b/files/opencs/clothing.png
index 88c9b6ab8b..88c9b6ab8b 100755..100644
--- a/files/opencs/clothing.png
+++ b/files/opencs/clothing.png
Binary files differ
diff --git a/files/opencs/container.png b/files/opencs/container.png
index 2a6ed01eb9..2a6ed01eb9 100755..100644
--- a/files/opencs/container.png
+++ b/files/opencs/container.png
Binary files differ
diff --git a/files/opencs/creature.png b/files/opencs/creature.png
index 99cf9c87ca..99cf9c87ca 100755..100644
--- a/files/opencs/creature.png
+++ b/files/opencs/creature.png
Binary files differ
diff --git a/files/opencs/defaultfilters b/files/opencs/defaultfilters
new file mode 100644
index 0000000000..0ac3c8db4b
--- /dev/null
+++ b/files/opencs/defaultfilters
Binary files differ
diff --git a/files/opencs/dialogoue-info.png b/files/opencs/dialogoue-info.png
new file mode 100644
index 0000000000..f6743d43c9
--- /dev/null
+++ b/files/opencs/dialogoue-info.png
Binary files differ
diff --git a/files/opencs/dialogoue-journal.png b/files/opencs/dialogoue-journal.png
new file mode 100644
index 0000000000..b6a95c5384
--- /dev/null
+++ b/files/opencs/dialogoue-journal.png
Binary files differ
diff --git a/files/opencs/dialogoue-regular.png b/files/opencs/dialogoue-regular.png
new file mode 100644
index 0000000000..f9b8d252d3
--- /dev/null
+++ b/files/opencs/dialogoue-regular.png
Binary files differ
diff --git a/files/opencs/dialogue-greeting.png b/files/opencs/dialogue-greeting.png
new file mode 100644
index 0000000000..a35e1fe6d1
--- /dev/null
+++ b/files/opencs/dialogue-greeting.png
Binary files differ
diff --git a/files/opencs/dialogue-persuasion.png b/files/opencs/dialogue-persuasion.png
new file mode 100644
index 0000000000..5bc5d61136
--- /dev/null
+++ b/files/opencs/dialogue-persuasion.png
Binary files differ
diff --git a/files/opencs/dialogue-speech.png b/files/opencs/dialogue-speech.png
new file mode 100644
index 0000000000..11eb9f1ca8
--- /dev/null
+++ b/files/opencs/dialogue-speech.png
Binary files differ
diff --git a/files/opencs/door.png b/files/opencs/door.png
index aa48858efa..aa48858efa 100755..100644
--- a/files/opencs/door.png
+++ b/files/opencs/door.png
Binary files differ
diff --git a/files/opencs/enchantment.png b/files/opencs/enchantment.png
new file mode 100644
index 0000000000..c90fb27ce3
--- /dev/null
+++ b/files/opencs/enchantment.png
Binary files differ
diff --git a/files/opencs/faction.png b/files/opencs/faction.png
new file mode 100644
index 0000000000..8ac1f5200c
--- /dev/null
+++ b/files/opencs/faction.png
Binary files differ
diff --git a/files/opencs/filter.png b/files/opencs/filter.png
new file mode 100644
index 0000000000..94a57ecd97
--- /dev/null
+++ b/files/opencs/filter.png
Binary files differ
diff --git a/files/opencs/globvar.png b/files/opencs/globvar.png
new file mode 100644
index 0000000000..646145f0f4
--- /dev/null
+++ b/files/opencs/globvar.png
Binary files differ
diff --git a/files/opencs/ingredient.png b/files/opencs/ingredient.png
index 6b36d008d2..564a930479 100755..100644
--- a/files/opencs/ingredient.png
+++ b/files/opencs/ingredient.png
Binary files differ
diff --git a/files/opencs/land.png b/files/opencs/land.png
new file mode 100644
index 0000000000..20dd321dda
--- /dev/null
+++ b/files/opencs/land.png
Binary files differ
diff --git a/files/opencs/landpaint.png b/files/opencs/landpaint.png
new file mode 100644
index 0000000000..711c0d8f5f
--- /dev/null
+++ b/files/opencs/landpaint.png
Binary files differ
diff --git a/files/opencs/leveled-creature.png b/files/opencs/leveled-creature.png
index ad4a7c6f83..ad4a7c6f83 100755..100644
--- a/files/opencs/leveled-creature.png
+++ b/files/opencs/leveled-creature.png
Binary files differ
diff --git a/files/opencs/light.png b/files/opencs/light.png
index c606fcd987..2765ef1d33 100755..100644
--- a/files/opencs/light.png
+++ b/files/opencs/light.png
Binary files differ
diff --git a/files/opencs/lockpick.png b/files/opencs/lockpick.png
index d9bd27f5e9..d9bd27f5e9 100755..100644
--- a/files/opencs/lockpick.png
+++ b/files/opencs/lockpick.png
Binary files differ
diff --git a/files/opencs/magic-effect.png b/files/opencs/magic-effect.png
new file mode 100644
index 0000000000..e672ffccb3
--- /dev/null
+++ b/files/opencs/magic-effect.png
Binary files differ
diff --git a/files/opencs/magicrabbit.png b/files/opencs/magicrabbit.png
new file mode 100644
index 0000000000..d1d7c8270b
--- /dev/null
+++ b/files/opencs/magicrabbit.png
Binary files differ
diff --git a/files/opencs/map.png b/files/opencs/map.png
new file mode 100644
index 0000000000..3653797cca
--- /dev/null
+++ b/files/opencs/map.png
Binary files differ
diff --git a/files/opencs/miscellaneous.png b/files/opencs/miscellaneous.png
index 744bcd9dbc..744bcd9dbc 100755..100644
--- a/files/opencs/miscellaneous.png
+++ b/files/opencs/miscellaneous.png
Binary files differ
diff --git a/files/opencs/modified.png b/files/opencs/modified.png
index d15ad827c3..39bd182ac2 100644
--- a/files/opencs/modified.png
+++ b/files/opencs/modified.png
Binary files differ
diff --git a/files/opencs/npc.png b/files/opencs/npc.png
index 7a07f26dfe..7a07f26dfe 100755..100644
--- a/files/opencs/npc.png
+++ b/files/opencs/npc.png
Binary files differ
diff --git a/files/opencs/potion.png b/files/opencs/potion.png
index 678f61fbf3..678f61fbf3 100755..100644
--- a/files/opencs/potion.png
+++ b/files/opencs/potion.png
Binary files differ
diff --git a/files/opencs/probe.png b/files/opencs/probe.png
index 01536186de..01536186de 100755..100644
--- a/files/opencs/probe.png
+++ b/files/opencs/probe.png
Binary files differ
diff --git a/files/opencs/race.png b/files/opencs/race.png
new file mode 100644
index 0000000000..94a2de696a
--- /dev/null
+++ b/files/opencs/race.png
Binary files differ
diff --git a/files/opencs/random-item.png b/files/opencs/random-item.png
new file mode 100644
index 0000000000..7b8e68e605
--- /dev/null
+++ b/files/opencs/random-item.png
Binary files differ
diff --git a/files/opencs/random.png b/files/opencs/random.png
new file mode 100644
index 0000000000..2667630f5c
--- /dev/null
+++ b/files/opencs/random.png
Binary files differ
diff --git a/files/opencs/raster/GMST.png b/files/opencs/raster/GMST.png
new file mode 100644
index 0000000000..f246202882
--- /dev/null
+++ b/files/opencs/raster/GMST.png
Binary files differ
diff --git a/files/opencs/raster/activator.png b/files/opencs/raster/activator.png
index 0446af22cf..32cc6f8a3c 100644
--- a/files/opencs/raster/activator.png
+++ b/files/opencs/raster/activator.png
Binary files differ
diff --git a/files/opencs/raster/attribute.png b/files/opencs/raster/attribute.png
new file mode 100644
index 0000000000..4aa5dc02e5
--- /dev/null
+++ b/files/opencs/raster/attribute.png
Binary files differ
diff --git a/files/opencs/raster/body-part.png b/files/opencs/raster/body-part.png
index 4aa5dc02e5..823e437126 100644
--- a/files/opencs/raster/body-part.png
+++ b/files/opencs/raster/body-part.png
Binary files differ
diff --git a/files/opencs/raster/book.png b/files/opencs/raster/book.png
index 3afa9e8aae..9d7669bd7e 100644
--- a/files/opencs/raster/book.png
+++ b/files/opencs/raster/book.png
Binary files differ
diff --git a/files/opencs/raster/filter.png b/files/opencs/raster/filter.png
new file mode 100644
index 0000000000..94a57ecd97
--- /dev/null
+++ b/files/opencs/raster/filter.png
Binary files differ
diff --git a/files/opencs/raster/ingredient.png b/files/opencs/raster/ingredient.png
index 6b36d008d2..564a930479 100644
--- a/files/opencs/raster/ingredient.png
+++ b/files/opencs/raster/ingredient.png
Binary files differ
diff --git a/files/opencs/raster/light.png b/files/opencs/raster/light.png
index c606fcd987..2765ef1d33 100644
--- a/files/opencs/raster/light.png
+++ b/files/opencs/raster/light.png
Binary files differ
diff --git a/files/opencs/raster/random.png b/files/opencs/raster/random.png
new file mode 100644
index 0000000000..2667630f5c
--- /dev/null
+++ b/files/opencs/raster/random.png
Binary files differ
diff --git a/files/opencs/raster/soundgen.png b/files/opencs/raster/soundgen.png
index 70ae43a1d7..222fc4c7fe 100644
--- a/files/opencs/raster/soundgen.png
+++ b/files/opencs/raster/soundgen.png
Binary files differ
diff --git a/files/opencs/raster/startup/big/configure.png b/files/opencs/raster/startup/big/configure.png
new file mode 100644
index 0000000000..f0be888a15
--- /dev/null
+++ b/files/opencs/raster/startup/big/configure.png
Binary files differ
diff --git a/files/opencs/raster/startup/big/create-addon.png b/files/opencs/raster/startup/big/create-addon.png
new file mode 100644
index 0000000000..fa059264ef
--- /dev/null
+++ b/files/opencs/raster/startup/big/create-addon.png
Binary files differ
diff --git a/files/opencs/raster/startup/big/edit-content.png b/files/opencs/raster/startup/big/edit-content.png
new file mode 100644
index 0000000000..dbb2602e5a
--- /dev/null
+++ b/files/opencs/raster/startup/big/edit-content.png
Binary files differ
diff --git a/files/opencs/raster/startup/big/new-game.png b/files/opencs/raster/startup/big/new-game.png
new file mode 100644
index 0000000000..5cec444178
--- /dev/null
+++ b/files/opencs/raster/startup/big/new-game.png
Binary files differ
diff --git a/files/opencs/raster/startup/small/configure.png b/files/opencs/raster/startup/small/configure.png
new file mode 100644
index 0000000000..e91b7f7731
--- /dev/null
+++ b/files/opencs/raster/startup/small/configure.png
Binary files differ
diff --git a/files/opencs/raster/startup/small/create-addon.png b/files/opencs/raster/startup/small/create-addon.png
new file mode 100644
index 0000000000..64fd138be5
--- /dev/null
+++ b/files/opencs/raster/startup/small/create-addon.png
Binary files differ
diff --git a/files/opencs/raster/startup/small/edit-content.png b/files/opencs/raster/startup/small/edit-content.png
new file mode 100644
index 0000000000..6297f1169c
--- /dev/null
+++ b/files/opencs/raster/startup/small/edit-content.png
Binary files differ
diff --git a/files/opencs/raster/startup/small/new-game.png b/files/opencs/raster/startup/small/new-game.png
new file mode 100644
index 0000000000..0d7d14c558
--- /dev/null
+++ b/files/opencs/raster/startup/small/new-game.png
Binary files differ
diff --git a/files/opencs/raster/static.png b/files/opencs/raster/static.png
index b53be12d9a..aedf2d30ee 100644
--- a/files/opencs/raster/static.png
+++ b/files/opencs/raster/static.png
Binary files differ
diff --git a/files/opencs/removed.png b/files/opencs/removed.png
index 2ca9e094be..2354bc7430 100644
--- a/files/opencs/removed.png
+++ b/files/opencs/removed.png
Binary files differ
diff --git a/files/opencs/repair.png b/files/opencs/repair.png
index 6cf1c0aacd..6cf1c0aacd 100755..100644
--- a/files/opencs/repair.png
+++ b/files/opencs/repair.png
Binary files differ
diff --git a/files/opencs/resources.qrc b/files/opencs/resources.qrc
index 321413763e..eadcf96977 100644
--- a/files/opencs/resources.qrc
+++ b/files/opencs/resources.qrc
@@ -1,29 +1,64 @@
<RCC>
<qresource prefix="/">
<file>opencs.png</file>
- <file>added.png</file>
- <file>modified.png</file>
- <file>removed.png</file>
- <file>base.png</file>
<file>activator.png</file>
- <file>apparatus.png</file>
- <file>armor.png</file>
- <file>book.png</file>
- <file>clothing.png</file>
- <file>container.png</file>
- <file>creature.png</file>
- <file>door.png</file>
- <file>ingredient.png</file>
- <file>leveled-creature.png</file>
- <file>leveled-item.png</file>
- <file>light.png</file>
- <file>lockpick.png</file>
- <file>miscellaneous.png</file>
- <file>npc.png</file>
- <file>potion.png</file>
- <file>probe.png</file>
- <file>repair.png</file>
- <file>static.png</file>
- <file>weapon.png</file>
+ <file>added.png</file>
+ <file>apparatus.png</file>
+ <file>armor.png</file>
+ <file>attribute.png</file>
+ <file>base.png</file>
+ <file>birthsign.png</file>
+ <file>body-part.png</file>
+ <file>book.png</file>
+ <file>cell.png</file>
+ <file>class.png</file>
+ <file>clothing.png</file>
+ <file>container.png</file>
+ <file>creature.png</file>
+ <file>dialogoue-info.png</file>
+ <file>dialogoue-journal.png</file>
+ <file>dialogoue-regular.png</file>
+ <file>dialogue-greeting.png</file>
+ <file>dialogue-persuasion.png</file>
+ <file>dialogue-speech.png</file>
+ <file>door.png</file>
+ <file>enchantment.png</file>
+ <file>faction.png</file>
+ <file>filter.png</file>
+ <file>globvar.png</file>
+ <file>GMST.png</file>
+ <file>Info.png</file>
+ <file>ingredient.png</file>
+ <file>landpaint.png</file>
+ <file>land.png</file>
+ <file>LandTexture.png</file>
+ <file>leveled-creature.png</file>
+ <file>light.png</file>
+ <file>lockpick.png</file>
+ <file>magic-effect.png</file>
+ <file>magicrabbit.png</file>
+ <file>map.png</file>
+ <file>miscellaneous.png</file>
+ <file>modified.png</file>
+ <file>npc.png</file>
+ <file>PathGrid.png</file>
+ <file>potion.png</file>
+ <file>probe.png</file>
+ <file>race.png</file>
+ <file>random-item.png</file>
+ <file>random.png</file>
+ <file>removed.png</file>
+ <file>repair.png</file>
+ <file>script.png</file>
+ <file>skill.png</file>
+ <file>soundgen.png</file>
+ <file>sound.png</file>
+ <file>spell.png</file>
+ <file>static.png</file>
+ <file>weapon.png</file>
+ <file alias="startup/create-addon">raster/startup/big/create-addon.png</file>
+ <file alias="startup/create-game">raster/startup/big/new-game.png</file>
+ <file alias="startup/edit-content">raster/startup/big/edit-content.png</file>
+ <file alias="startup/configure">raster/startup/small/configure.png</file>
</qresource>
</RCC>
diff --git a/files/opencs/scalable/referenceable-record/.directory b/files/opencs/scalable/referenceable-record/.directory
index c633c38a9a..98e1b7f92a 100644
--- a/files/opencs/scalable/referenceable-record/.directory
+++ b/files/opencs/scalable/referenceable-record/.directory
@@ -1,7 +1,7 @@
[Dolphin]
GroupedSorting=true
SortFoldersFirst=false
-Timestamp=2013,8,11,16,50,43
+Timestamp=2013,8,25,18,35,16
Version=3
ViewMode=2
VisibleRoles=Compact_text,Compact_size
diff --git a/files/opencs/scalable/referenceable-record/book2.svgz b/files/opencs/scalable/referenceable-record/book2.svgz
new file mode 100644
index 0000000000..4535a2fce4
--- /dev/null
+++ b/files/opencs/scalable/referenceable-record/book2.svgz
Binary files differ
diff --git a/files/opencs/scalable/referenceable-record/miscellaneous.svg b/files/opencs/scalable/referenceable-record/miscellaneous.svg
deleted file mode 100644
index 96522048cb..0000000000
--- a/files/opencs/scalable/referenceable-record/miscellaneous.svg
+++ /dev/null
@@ -1,965 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" standalone="no"?>
-<!-- Created with Inkscape (http://www.inkscape.org/) -->
-
-<svg
- xmlns:dc="http://purl.org/dc/elements/1.1/"
- xmlns:cc="http://creativecommons.org/ns#"
- xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
- xmlns:svg="http://www.w3.org/2000/svg"
- xmlns="http://www.w3.org/2000/svg"
- xmlns:xlink="http://www.w3.org/1999/xlink"
- xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
- xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
- width="48"
- height="48"
- id="svg2"
- version="1.1"
- inkscape:version="0.48.4 r9939"
- sodipodi:docname="miscelanius.svg">
- <sodipodi:namedview
- id="base"
- pagecolor="#ffffff"
- bordercolor="#666666"
- borderopacity="1.0"
- inkscape:pageopacity="0.0"
- inkscape:pageshadow="2"
- inkscape:zoom="8.0000002"
- inkscape:cx="3.9119117"
- inkscape:cy="-1.8033034"
- inkscape:document-units="px"
- inkscape:current-layer="g4862"
- showgrid="false"
- showguides="true"
- inkscape:guide-bbox="true"
- inkscape:window-width="1280"
- inkscape:window-height="994"
- inkscape:window-x="0"
- inkscape:window-y="30"
- inkscape:window-maximized="1"
- inkscape:snap-page="true"
- inkscape:snap-bbox="true"
- inkscape:bbox-paths="true"
- inkscape:bbox-nodes="true"
- inkscape:snap-bbox-edge-midpoints="true"
- inkscape:snap-bbox-midpoints="true"
- inkscape:object-paths="true"
- inkscape:snap-intersection-paths="false"
- inkscape:object-nodes="true"
- inkscape:snap-global="true"
- inkscape:snap-smooth-nodes="true"
- inkscape:snap-grids="false" />
- <defs
- id="defs4">
- <linearGradient
- id="linearGradient3902"
- inkscape:collect="always">
- <stop
- id="stop3904"
- offset="0"
- style="stop-color:#000000;stop-opacity:1;" />
- <stop
- id="stop3906"
- offset="1"
- style="stop-color:#000000;stop-opacity:0;" />
- </linearGradient>
- <linearGradient
- id="linearGradient3886"
- inkscape:collect="always">
- <stop
- id="stop3888"
- offset="0"
- style="stop-color:#fff226;stop-opacity:1;" />
- <stop
- id="stop3890"
- offset="1"
- style="stop-color:#fff226;stop-opacity:0;" />
- </linearGradient>
- <linearGradient
- id="linearGradient9248">
- <stop
- id="stop9250"
- offset="0"
- style="stop-color:#ffffff;stop-opacity:1;" />
- <stop
- id="stop9252"
- offset="1"
- style="stop-color:#b4b4b4;stop-opacity:1;" />
- </linearGradient>
- <linearGradient
- id="linearGradient8521">
- <stop
- id="stop8523"
- offset="0"
- style="stop-color:#00105d;stop-opacity:1;" />
- <stop
- id="stop8525"
- offset="1"
- style="stop-color:#00105d;stop-opacity:0;" />
- </linearGradient>
- <linearGradient
- id="linearGradient7487">
- <stop
- style="stop-color:#000e50;stop-opacity:1;"
- offset="0"
- id="stop7489" />
- <stop
- style="stop-color:#000000;stop-opacity:1;"
- offset="1"
- id="stop7491" />
- </linearGradient>
- <linearGradient
- id="linearGradient6034">
- <stop
- style="stop-color:#ffffff;stop-opacity:1;"
- offset="0"
- id="stop6036" />
- <stop
- style="stop-color:#b3bbad;stop-opacity:1;"
- offset="1"
- id="stop6038" />
- </linearGradient>
- <linearGradient
- id="linearGradient6815">
- <stop
- id="stop6817"
- offset="0"
- style="stop-color:#000000;stop-opacity:1;" />
- <stop
- style="stop-color:#3c3c3c;stop-opacity:0.58823532;"
- offset="0.40229002"
- id="stop6825" />
- <stop
- id="stop6819"
- offset="1"
- style="stop-color:#3c3c3c;stop-opacity:0;" />
- </linearGradient>
- <linearGradient
- id="linearGradient4022">
- <stop
- id="stop4024"
- offset="0"
- style="stop-color:#204a87;stop-opacity:1;" />
- <stop
- id="stop4026"
- offset="1"
- style="stop-color:#729fcf;stop-opacity:1;" />
- </linearGradient>
- <linearGradient
- id="linearGradient3723">
- <stop
- id="stop3725"
- offset="0"
- style="stop-color:#ffffff;stop-opacity:0.78431374;" />
- <stop
- id="stop3727"
- offset="1"
- style="stop-color:#ffffff;stop-opacity:0;" />
- </linearGradient>
- <linearGradient
- id="linearGradient3715">
- <stop
- id="stop3717"
- offset="0"
- style="stop-color:#99bbd4;stop-opacity:1;" />
- <stop
- id="stop3719"
- offset="1"
- style="stop-color:#5d93ba;stop-opacity:1;" />
- </linearGradient>
- <linearGradient
- id="linearGradient3707">
- <stop
- id="stop3709"
- offset="0"
- style="stop-color:#a6c4d9;stop-opacity:0.78431374;" />
- <stop
- id="stop3711"
- offset="1"
- style="stop-color:#75a3c3;stop-opacity:1;" />
- </linearGradient>
- <inkscape:perspective
- id="perspective10"
- inkscape:persp3d-origin="372.04724 : 350.78739 : 1"
- inkscape:vp_z="744.09448 : 526.18109 : 1"
- inkscape:vp_y="0 : 1000 : 0"
- inkscape:vp_x="0 : 526.18109 : 1"
- sodipodi:type="inkscape:persp3d" />
- <inkscape:perspective
- sodipodi:type="inkscape:persp3d"
- inkscape:vp_x="0 : 0.5 : 1"
- inkscape:vp_y="0 : 1000 : 0"
- inkscape:vp_z="1 : 0.5 : 1"
- inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
- id="perspective2920" />
- <linearGradient
- gradientTransform="translate(0.2341189,5.74082)"
- gradientUnits="userSpaceOnUse"
- y2="1029.8864"
- x2="63.765881"
- y1="949.3266"
- x1="63.765881"
- id="linearGradient3713"
- xlink:href="#linearGradient3707"
- inkscape:collect="always" />
- <linearGradient
- gradientTransform="translate(0.2341196,6.0908086)"
- gradientUnits="userSpaceOnUse"
- y2="983.41931"
- x2="63.765881"
- y1="936.95227"
- x1="63.765881"
- id="linearGradient3721"
- xlink:href="#linearGradient3715"
- inkscape:collect="always" />
- <linearGradient
- gradientTransform="translate(0.2341189,5.74082)"
- gradientUnits="userSpaceOnUse"
- y2="1030.7611"
- x2="37.375645"
- y1="948.8266"
- x1="37.375645"
- id="linearGradient3729"
- xlink:href="#linearGradient3723"
- inkscape:collect="always" />
- <linearGradient
- y2="983.41931"
- x2="63.765881"
- y1="936.95227"
- x1="63.765881"
- gradientTransform="translate(0.2341196,6.0908086)"
- gradientUnits="userSpaceOnUse"
- id="linearGradient3735"
- xlink:href="#linearGradient3715"
- inkscape:collect="always" />
- <linearGradient
- y2="1029.8864"
- x2="63.765881"
- y1="949.3266"
- x1="63.765881"
- gradientTransform="translate(0.2341189,5.74082)"
- gradientUnits="userSpaceOnUse"
- id="linearGradient3737"
- xlink:href="#linearGradient3707"
- inkscape:collect="always" />
- <linearGradient
- y2="1030.7611"
- x2="37.375645"
- y1="948.8266"
- x1="37.375645"
- gradientTransform="translate(0.2341189,5.74082)"
- gradientUnits="userSpaceOnUse"
- id="linearGradient3739"
- xlink:href="#linearGradient3723"
- inkscape:collect="always" />
- <linearGradient
- y2="1029.8864"
- x2="63.765881"
- y1="949.3266"
- x1="63.765881"
- gradientTransform="matrix(1.0066488,0,0,1.0066488,0.21965498,-1.1089658)"
- gradientUnits="userSpaceOnUse"
- id="linearGradient3742"
- xlink:href="#linearGradient3707"
- inkscape:collect="always" />
- <linearGradient
- y2="1030.7611"
- x2="37.375645"
- y1="948.8266"
- x1="37.375645"
- gradientTransform="matrix(1.0066488,0,0,1.0066488,0.21965498,-1.1089658)"
- gradientUnits="userSpaceOnUse"
- id="linearGradient3744"
- xlink:href="#linearGradient3723"
- inkscape:collect="always" />
- <linearGradient
- y2="983.41931"
- x2="63.765881"
- y1="936.95227"
- x1="63.765881"
- gradientTransform="matrix(1.0066488,0,0,1.0066488,0.21965567,-0.75665045)"
- gradientUnits="userSpaceOnUse"
- id="linearGradient3747"
- xlink:href="#linearGradient3715"
- inkscape:collect="always" />
- <linearGradient
- y2="983.41931"
- x2="63.765881"
- y1="936.95227"
- x1="63.765881"
- gradientTransform="matrix(1.0066488,0,0,1.0066488,0.21965567,-0.75665045)"
- gradientUnits="userSpaceOnUse"
- id="linearGradient3753"
- xlink:href="#linearGradient3715"
- inkscape:collect="always" />
- <linearGradient
- y2="1029.8864"
- x2="63.765881"
- y1="949.3266"
- x1="63.765881"
- gradientTransform="matrix(1.0066488,0,0,1.0066488,0.21965498,-1.1089658)"
- gradientUnits="userSpaceOnUse"
- id="linearGradient3755"
- xlink:href="#linearGradient3707"
- inkscape:collect="always" />
- <linearGradient
- y2="1030.7611"
- x2="37.375645"
- y1="948.8266"
- x1="37.375645"
- gradientTransform="matrix(1.0066488,0,0,1.0066488,0.21965498,-1.1089658)"
- gradientUnits="userSpaceOnUse"
- id="linearGradient3757"
- xlink:href="#linearGradient3723"
- inkscape:collect="always" />
- <linearGradient
- gradientTransform="matrix(0.91716429,0,0,0.91716429,2.2512556,85.18512)"
- gradientUnits="userSpaceOnUse"
- y2="1008.9376"
- x2="47.902649"
- y1="1048.3364"
- x1="14.991861"
- id="linearGradient4028"
- xlink:href="#linearGradient4022"
- inkscape:collect="always" />
- <linearGradient
- inkscape:collect="always"
- xlink:href="#linearGradient3818"
- id="linearGradient5433"
- x1="-14.939182"
- y1="166.73387"
- x2="-15.495684"
- y2="164.65698"
- gradientUnits="userSpaceOnUse"
- gradientTransform="matrix(0.71906912,0,0,0.71906912,35.096859,924.87424)" />
- <linearGradient
- id="linearGradient3818">
- <stop
- style="stop-color:#1e1e1e;stop-opacity:1;"
- offset="0"
- id="stop3820" />
- <stop
- style="stop-color:#000000;stop-opacity:0;"
- offset="1"
- id="stop3822" />
- </linearGradient>
- <linearGradient
- id="linearGradient3715-2">
- <stop
- style="stop-color:#ffffff;stop-opacity:1;"
- offset="0"
- id="stop3717-4" />
- <stop
- style="stop-color:#b3bbad;stop-opacity:1;"
- offset="1"
- id="stop3719-9" />
- </linearGradient>
- <linearGradient
- id="linearGradient5299">
- <stop
- style="stop-color:#000e50;stop-opacity:1;"
- offset="0"
- id="stop5301" />
- <stop
- style="stop-color:#000000;stop-opacity:1;"
- offset="1"
- id="stop5303" />
- </linearGradient>
- <radialGradient
- r="29.000444"
- fy="119.59179"
- fx="-172.875"
- cy="119.59179"
- cx="-172.875"
- gradientTransform="matrix(1.0541003,0.65674043,-0.42405323,0.68062603,240.54684,45.0811)"
- gradientUnits="userSpaceOnUse"
- id="radialGradient6812"
- xlink:href="#linearGradient3715-2"
- inkscape:collect="always" />
- <linearGradient
- y2="965.56183"
- x2="63.765881"
- y1="941.44623"
- x1="63.765881"
- gradientTransform="matrix(0.37749331,0,0,0.37749331,-0.0711918,657.55701)"
- gradientUnits="userSpaceOnUse"
- id="linearGradient2843"
- xlink:href="#linearGradient3715-6"
- inkscape:collect="always" />
- <linearGradient
- id="linearGradient3715-6">
- <stop
- id="stop3717-6"
- offset="0"
- style="stop-color:#99bbd4;stop-opacity:1;" />
- <stop
- id="stop3719-4"
- offset="1"
- style="stop-color:#5d93ba;stop-opacity:1;" />
- </linearGradient>
- <linearGradient
- inkscape:collect="always"
- xlink:href="#linearGradient3715-6"
- id="linearGradient3184"
- gradientUnits="userSpaceOnUse"
- gradientTransform="matrix(-0.37749331,0,0,0.37749331,4.1838142,536.26868)"
- x1="63.765881"
- y1="941.44623"
- x2="63.765881"
- y2="965.56183" />
- <linearGradient
- inkscape:collect="always"
- xlink:href="#linearGradient3715-6"
- id="linearGradient3321"
- gradientUnits="userSpaceOnUse"
- gradientTransform="matrix(-0.28231332,0,0,0.28231332,64.982195,664.15172)"
- x1="63.765881"
- y1="941.44623"
- x2="63.765881"
- y2="965.56183" />
- <linearGradient
- id="linearGradient6815-6">
- <stop
- id="stop6817-4"
- offset="0"
- style="stop-color:#000000;stop-opacity:1;" />
- <stop
- style="stop-color:#3c3c3c;stop-opacity:0.58823532;"
- offset="0.40229002"
- id="stop6825-9" />
- <stop
- id="stop6819-5"
- offset="1"
- style="stop-color:#3c3c3c;stop-opacity:0;" />
- </linearGradient>
- <linearGradient
- id="linearGradient3715-2-4">
- <stop
- style="stop-color:#ffffff;stop-opacity:1;"
- offset="0"
- id="stop3717-4-8" />
- <stop
- style="stop-color:#b3bbad;stop-opacity:1;"
- offset="1"
- id="stop3719-9-7" />
- </linearGradient>
- <radialGradient
- r="28.421875"
- fy="116.19179"
- fx="-182.4375"
- cy="116.19179"
- cx="-182.4375"
- gradientTransform="matrix(0.30667246,1.5835715,-1.396495,0.27044345,218.94267,1272.3725)"
- gradientUnits="userSpaceOnUse"
- id="radialGradient5641-1"
- xlink:href="#linearGradient5299-7"
- inkscape:collect="always" />
- <linearGradient
- id="linearGradient5299-7">
- <stop
- style="stop-color:#000e50;stop-opacity:1;"
- offset="0"
- id="stop5301-2" />
- <stop
- style="stop-color:#000000;stop-opacity:1;"
- offset="1"
- id="stop5303-7" />
- </linearGradient>
- <linearGradient
- y2="350.56357"
- x2="518.24652"
- y1="536.11566"
- x1="553.62225"
- gradientTransform="translate(-26.263966,56.568543)"
- gradientUnits="userSpaceOnUse"
- id="linearGradient4078-954"
- xlink:href="#linearGradient3955-87-471"
- inkscape:collect="always" />
- <linearGradient
- inkscape:collect="always"
- id="linearGradient3955-87-471">
- <stop
- style="stop-color:#436123;stop-opacity:1"
- offset="0"
- id="stop4122" />
- <stop
- id="stop4124"
- offset="0.04243463"
- style="stop-color:#74984d;stop-opacity:1;" />
- <stop
- style="stop-color:#74984d;stop-opacity:1"
- offset="1"
- id="stop4126" />
- </linearGradient>
- <pattern
- patternUnits="userSpaceOnUse"
- width="2"
- height="1"
- patternTransform="matrix(0,4.4721359,-4.4721359,0,-50.004131,-3.0322266e-6)"
- id="Strips1_1"
- inkscape:stockid="Stripes 1:1">
- <rect
- style="fill:black;stroke:none"
- x="0"
- y="-0.5"
- width="1"
- height="2"
- id="rect3917" />
- </pattern>
- <linearGradient
- inkscape:collect="always"
- xlink:href="#linearGradient6034"
- id="linearGradient6042"
- gradientUnits="userSpaceOnUse"
- x1="-2256.6802"
- y1="1067.036"
- x2="37.487514"
- y2="2532.4438"
- gradientTransform="translate(-1.6900304,-354.84909)" />
- <linearGradient
- y2="2444.7776"
- x2="-2151.6707"
- y1="2903.8035"
- x1="-2148.2864"
- gradientUnits="userSpaceOnUse"
- id="linearGradient8509"
- xlink:href="#linearGradient7487"
- inkscape:collect="always"
- gradientTransform="translate(-1.6900304,-354.84909)" />
- <linearGradient
- gradientUnits="userSpaceOnUse"
- y2="3353.4497"
- x2="-1962.6486"
- y1="2540.8635"
- x1="-1962.6486"
- id="linearGradient8527"
- xlink:href="#linearGradient7487"
- inkscape:collect="always" />
- <linearGradient
- spreadMethod="reflect"
- gradientUnits="userSpaceOnUse"
- y2="2914.2673"
- x2="-115.04873"
- y1="2899.3862"
- x1="-115.04873"
- id="linearGradient9254"
- xlink:href="#linearGradient9248"
- inkscape:collect="always"
- gradientTransform="translate(-1.6900304,-354.84909)" />
- <radialGradient
- gradientUnits="userSpaceOnUse"
- gradientTransform="matrix(1,0,0,0.60717495,0,6.6355278)"
- r="3.1054714"
- fy="16.891813"
- fx="29.111721"
- cy="16.891813"
- cx="29.111721"
- id="radialGradient3892"
- xlink:href="#linearGradient3886"
- inkscape:collect="always" />
- <radialGradient
- gradientUnits="userSpaceOnUse"
- gradientTransform="matrix(2.1494315,0.36121083,-0.30519899,1.8161266,2.9871553,-34.404392)"
- r="15.46875"
- fy="32.971859"
- fx="13.599908"
- cy="32.971859"
- cx="13.599908"
- id="radialGradient3908"
- xlink:href="#linearGradient3902"
- inkscape:collect="always" />
- <inkscape:path-effect
- fuse_tolerance="0"
- vertical_pattern="false"
- prop_units="false"
- tang_offset="0"
- normal_offset="0"
- spacing="0"
- scale_y_rel="false"
- prop_scale="1"
- copytype="single_stretched"
- pattern="m 1273.479,-26681.071 0,10 10,-5 z"
- is_visible="true"
- id="path-effect4754"
- effect="skeletal" />
- <inkscape:path-effect
- effect="skeletal"
- id="path-effect4760"
- is_visible="true"
- pattern="m 1315.479,-26621.071 0,10 10,-5 z"
- copytype="single_stretched"
- prop_scale="1"
- scale_y_rel="false"
- spacing="0"
- normal_offset="0"
- tang_offset="0"
- prop_units="false"
- vertical_pattern="false"
- fuse_tolerance="0" />
- <inkscape:path-effect
- effect="skeletal"
- id="path-effect2991"
- is_visible="true"
- pattern="m 595.66194,-26736.611 0,10 10,-5 z"
- copytype="single_stretched"
- prop_scale="1"
- scale_y_rel="false"
- spacing="0"
- normal_offset="0"
- tang_offset="0"
- prop_units="false"
- vertical_pattern="false"
- fuse_tolerance="0" />
- <radialGradient
- inkscape:collect="always"
- xlink:href="#linearGradient4904"
- id="radialGradient4910"
- cx="270.45764"
- cy="499.72882"
- fx="270.45764"
- fy="499.72882"
- r="96.228813"
- gradientTransform="matrix(1,0,0,0.44359312,0,278.05255)"
- gradientUnits="userSpaceOnUse" />
- <linearGradient
- id="linearGradient4904">
- <stop
- style="stop-color:#321b00;stop-opacity:1;"
- offset="0"
- id="stop4906" />
- <stop
- style="stop-color:#653700;stop-opacity:1;"
- offset="1"
- id="stop4908" />
- </linearGradient>
- <linearGradient
- inkscape:collect="always"
- xlink:href="#linearGradient4787"
- id="linearGradient4793"
- x1="270.45764"
- y1="458.54239"
- x2="270.45764"
- y2="540.91528"
- gradientUnits="userSpaceOnUse" />
- <linearGradient
- inkscape:collect="always"
- id="linearGradient4787">
- <stop
- style="stop-color:#000000;stop-opacity:1;"
- offset="0"
- id="stop4789" />
- <stop
- style="stop-color:#000000;stop-opacity:0;"
- offset="1"
- id="stop4791" />
- </linearGradient>
- <radialGradient
- inkscape:collect="always"
- xlink:href="#linearGradient4805"
- id="radialGradient4813"
- cx="279.13174"
- cy="537.41302"
- fx="279.13174"
- fy="537.41302"
- r="94.728813"
- gradientTransform="matrix(1.0793238,-0.1626202,0.09156796,0.60774413,-71.351608,234.89611)"
- gradientUnits="userSpaceOnUse" />
- <linearGradient
- id="linearGradient4805">
- <stop
- style="stop-color:#cf0000;stop-opacity:1;"
- offset="0"
- id="stop4807" />
- <stop
- style="stop-color:#800000;stop-opacity:1;"
- offset="1"
- id="stop4809" />
- </linearGradient>
- <linearGradient
- inkscape:collect="always"
- xlink:href="#linearGradient4850"
- id="linearGradient4856"
- x1="9"
- y1="314.39062"
- x2="136.21875"
- y2="314.39062"
- gradientUnits="userSpaceOnUse" />
- <linearGradient
- id="linearGradient4850">
- <stop
- style="stop-color:#232620;stop-opacity:1;"
- offset="0"
- id="stop4852" />
- <stop
- id="stop4858"
- offset="0.5"
- style="stop-color:#ffffff;stop-opacity:0;" />
- <stop
- style="stop-color:#232620;stop-opacity:1;"
- offset="1"
- id="stop4854" />
- </linearGradient>
- <linearGradient
- inkscape:collect="always"
- xlink:href="#linearGradient4795"
- id="linearGradient4801"
- x1="179.76239"
- y1="205.93243"
- x2="211.7963"
- y2="205.93243"
- gradientUnits="userSpaceOnUse" />
- <linearGradient
- id="linearGradient4795">
- <stop
- style="stop-color:#800000;stop-opacity:1;"
- offset="0"
- id="stop4797" />
- <stop
- id="stop4803"
- offset="0.5"
- style="stop-color:#d07200;stop-opacity:1;" />
- <stop
- style="stop-color:#800000;stop-opacity:1;"
- offset="1"
- id="stop4799" />
- </linearGradient>
- <radialGradient
- inkscape:collect="always"
- xlink:href="#linearGradient4805"
- id="radialGradient4872"
- gradientUnits="userSpaceOnUse"
- gradientTransform="matrix(1.0793238,-0.1626202,0.09156796,0.60774413,-71.351608,234.89611)"
- cx="279.13174"
- cy="537.41302"
- fx="279.13174"
- fy="537.41302"
- r="94.728813" />
- <linearGradient
- id="linearGradient4965">
- <stop
- style="stop-color:#cf0000;stop-opacity:1;"
- offset="0"
- id="stop4967" />
- <stop
- style="stop-color:#800000;stop-opacity:1;"
- offset="1"
- id="stop4969" />
- </linearGradient>
- <linearGradient
- inkscape:collect="always"
- xlink:href="#linearGradient4850"
- id="linearGradient4874"
- gradientUnits="userSpaceOnUse"
- x1="9"
- y1="314.39062"
- x2="136.21875"
- y2="314.39062" />
- <linearGradient
- id="linearGradient4972">
- <stop
- style="stop-color:#232620;stop-opacity:1;"
- offset="0"
- id="stop4974" />
- <stop
- id="stop4976"
- offset="0.5"
- style="stop-color:#ffffff;stop-opacity:0;" />
- <stop
- style="stop-color:#232620;stop-opacity:1;"
- offset="1"
- id="stop4978" />
- </linearGradient>
- <radialGradient
- inkscape:collect="always"
- xlink:href="#linearGradient4882"
- id="radialGradient4888"
- cx="195.79498"
- cy="55.193817"
- fx="195.79498"
- fy="55.193817"
- r="30.780195"
- gradientTransform="matrix(0.68778076,0,0,0.83721193,61.130961,8.984896)"
- gradientUnits="userSpaceOnUse" />
- <linearGradient
- id="linearGradient4882">
- <stop
- style="stop-color:#824700;stop-opacity:1;"
- offset="0"
- id="stop4884" />
- <stop
- style="stop-color:#d07200;stop-opacity:1;"
- offset="1"
- id="stop4886" />
- </linearGradient>
- <linearGradient
- inkscape:collect="always"
- xlink:href="#linearGradient4892"
- id="linearGradient4902"
- x1="165.0148"
- y1="55.193817"
- x2="226.5752"
- y2="55.193817"
- gradientUnits="userSpaceOnUse"
- gradientTransform="matrix(0.68778076,0,0,0.68778076,61.130961,17.232572)" />
- <linearGradient
- id="linearGradient4892">
- <stop
- style="stop-color:#000000;stop-opacity:1;"
- offset="0"
- id="stop4894" />
- <stop
- id="stop4900"
- offset="0.5"
- style="stop-color:#595d56;stop-opacity:0;" />
- <stop
- style="stop-color:#000000;stop-opacity:1;"
- offset="1"
- id="stop4896" />
- </linearGradient>
- <linearGradient
- y2="55.193817"
- x2="226.5752"
- y1="55.193817"
- x1="165.0148"
- gradientTransform="matrix(0.68778076,0,0,0.68778076,61.130961,17.232572)"
- gradientUnits="userSpaceOnUse"
- id="linearGradient5008"
- xlink:href="#linearGradient4892"
- inkscape:collect="always" />
- </defs>
- <metadata
- id="metadata7">
- <rdf:RDF>
- <cc:Work
- rdf:about="">
- <dc:format>image/svg+xml</dc:format>
- <dc:type
- rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
- <dc:title />
- </cc:Work>
- </rdf:RDF>
- </metadata>
- <g
- transform="translate(0,-1004.3622)"
- id="layer1"
- inkscape:groupmode="layer"
- inkscape:label="Livello 1">
- <g
- id="g3891"
- transform="matrix(0.02092262,0,0,0.02092262,47.215663,982.03701)">
- <path
- style="fill:#fa0000;fill-opacity:1;stroke:none"
- d="m -684.61499,2674.2647 0,170.9884 -318.88181,0 520.49211,515.9507 520.492204,-515.9507 -318.881804,0 0,-170.9884 -403.2207,0 z"
- id="path5146"
- inkscape:connector-curvature="0" />
- <g
- transform="matrix(5.0625238,0,0,5.0625238,-2302.2429,918.07499)"
- id="g4912">
- <g
- transform="matrix(-1,0,0,1,391.56935,0.01189)"
- id="g4860">
- <g
- id="g4862">
- <path
- sodipodi:type="arc"
- style="fill:url(#radialGradient4872);fill-opacity:1;stroke:none"
- id="path4864"
- sodipodi:cx="270.45764"
- sodipodi:cy="499.72882"
- sodipodi:rx="94.728813"
- sodipodi:ry="41.18644"
- d="m 365.18645,499.72882 c 0,22.74664 -42.41153,41.18644 -94.72881,41.18644 -52.31728,0 -94.72881,-18.4398 -94.72881,-41.18644 0,-22.74664 42.41153,-41.18644 94.72881,-41.18644 52.31728,0 94.72881,18.4398 94.72881,41.18644 z"
- transform="matrix(-0.67149758,0,0,0.67149758,254.22789,-33.552002)" />
- <path
- style="fill:none;stroke:#d07200;stroke-width:3;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
- d="M 130.40221,313.59159 76.506851,145.58186 16.670251,315.18688"
- id="path4866"
- inkscape:connector-curvature="0" />
- <path
- style="fill:none;stroke:#d07200;stroke-width:3;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
- d="m 76.506851,145.58186 -3.8906,128.77624"
- id="path4868"
- inkscape:connector-curvature="0" />
- <path
- inkscape:connector-curvature="0"
- id="path4870"
- d="M 9.375,299.125 C 9.1474242,300.07637 9,301.02245 9,302 c 0,15.27432 28.494074,27.65625 63.625,27.65625 35.13093,0 63.59375,-12.38193 63.59375,-27.65625 0,-0.97755 -0.11617,-1.92363 -0.34375,-2.875 -3.35909,13.89991 -30.39038,24.71875 -63.25,24.71875 -32.85962,0 -59.890909,-10.81884 -63.25,-24.71875 z"
- style="opacity:0.5;fill:url(#linearGradient4874);fill-opacity:1;stroke:none" />
- </g>
- </g>
- <path
- transform="translate(-74.678308,-139.57606)"
- sodipodi:type="arc"
- style="fill:url(#radialGradient4910);fill-opacity:1;stroke:#000023;stroke-width:3;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
- id="path3344"
- sodipodi:cx="270.45764"
- sodipodi:cy="499.72882"
- sodipodi:rx="94.728813"
- sodipodi:ry="41.18644"
- d="m 365.18645,499.72882 c 0,22.74664 -42.41153,41.18644 -94.72881,41.18644 -52.31728,0 -94.72881,-18.4398 -94.72881,-41.18644 0,-22.74664 42.41153,-41.18644 94.72881,-41.18644 52.31728,0 94.72881,18.4398 94.72881,41.18644 z" />
- <path
- inkscape:connector-curvature="0"
- id="rect3350"
- d="m 76.5,126.5 0,19.09375 c 0,-4.64658 6.52034,-8.4375 14.5625,-8.4375 8.04215,0 14.5625,3.79092 14.5625,8.4375 l 180.3125,0 c 0,-4.64658 6.52035,-8.4375 14.5625,-8.4375 8.04215,0 14.5625,3.79092 14.5625,8.4375 l 0,-19.09375 -238.5625,0 z"
- style="fill:#d07200;fill-opacity:1;stroke:none" />
- <path
- d="m 365.18645,499.72882 c 0,22.74664 -42.41153,41.18644 -94.72881,41.18644 -52.31728,0 -94.72881,-18.4398 -94.72881,-41.18644 0,-22.74664 42.41153,-41.18644 94.72881,-41.18644 52.31728,0 94.72881,18.4398 94.72881,41.18644 z"
- sodipodi:ry="41.18644"
- sodipodi:rx="94.728813"
- sodipodi:cy="499.72882"
- sodipodi:cx="270.45764"
- id="path4785"
- style="opacity:0.5;fill:url(#linearGradient4793);fill-opacity:1;stroke:none"
- sodipodi:type="arc"
- transform="translate(-74.678303,-139.57606)" />
- <g
- id="g3358">
- <g
- id="g4832">
- <path
- transform="matrix(-0.67149758,0,0,0.67149758,254.22789,-33.552002)"
- d="m 365.18645,499.72882 c 0,22.74664 -42.41153,41.18644 -94.72881,41.18644 -52.31728,0 -94.72881,-18.4398 -94.72881,-41.18644 0,-22.74664 42.41153,-41.18644 94.72881,-41.18644 52.31728,0 94.72881,18.4398 94.72881,41.18644 z"
- sodipodi:ry="41.18644"
- sodipodi:rx="94.728813"
- sodipodi:cy="499.72882"
- sodipodi:cx="270.45764"
- id="path3388"
- style="fill:url(#radialGradient4813);fill-opacity:1;stroke:none"
- sodipodi:type="arc" />
- <path
- inkscape:connector-curvature="0"
- id="path3390"
- d="M 130.40221,313.59159 76.506851,145.58186 16.670251,315.18688"
- style="fill:none;stroke:#d07200;stroke-width:3;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" />
- <path
- inkscape:connector-curvature="0"
- id="path3392"
- d="m 76.506851,145.58186 -3.8906,128.77624"
- style="fill:none;stroke:#d07200;stroke-width:3;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" />
- <path
- inkscape:connector-curvature="0"
- style="opacity:0.5;fill:url(#linearGradient4856);fill-opacity:1;stroke:none"
- d="M 9.375,299.125 C 9.1474242,300.07637 9,301.02245 9,302 c 0,15.27432 28.494074,27.65625 63.625,27.65625 35.13093,0 63.59375,-12.38193 63.59375,-27.65625 0,-0.97755 -0.11617,-1.92363 -0.34375,-2.875 -3.35909,13.89991 -30.39038,24.71875 -63.25,24.71875 -32.85962,0 -59.890909,-10.81884 -63.25,-24.71875 z"
- id="path4821" />
- </g>
- </g>
- <rect
- y="51.71209"
- x="179.76239"
- height="308.44067"
- width="32.033897"
- id="rect3340"
- style="fill:url(#linearGradient4801);fill-opacity:1;stroke:none" />
- <path
- inkscape:connector-curvature="0"
- id="path4876"
- d="m 195.7894,29.424271 c -8.89509,0 -16.09832,7.214351 -16.09832,16.109438 0,0.172769 0.005,0.339601 0.0111,0.511058 -3.16547,3.699588 -5.07725,8.503386 -5.07725,13.754126 0,11.690687 9.47378,21.16447 21.16447,21.16447 11.69069,0 21.17558,-9.473783 21.17558,-21.16447 0,-5.25074 -1.91178,-10.054538 -5.07725,-13.754126 0.005,-0.171457 0.0111,-0.338289 0.0111,-0.511058 0,-8.895087 -7.21435,-16.109438 -16.10943,-16.109438 z"
- style="fill:url(#radialGradient4888);fill-opacity:1;stroke:none" />
- <path
- style="opacity:0.35;fill:url(#linearGradient5008);fill-opacity:1;stroke:none"
- d="m 195.7894,29.424271 c -8.89509,0 -16.09832,7.214351 -16.09832,16.109438 0,0.172769 0.005,0.339601 0.0111,0.511058 -3.16547,3.699588 -5.07725,8.503386 -5.07725,13.754126 0,11.690687 9.47378,21.16447 21.16447,21.16447 11.69069,0 21.17558,-9.473783 21.17558,-21.16447 0,-5.25074 -1.91178,-10.054538 -5.07725,-13.754126 0.005,-0.171457 0.0111,-0.338289 0.0111,-0.511058 0,-8.895087 -7.21435,-16.109438 -16.10943,-16.109438 z"
- id="path4890"
- inkscape:connector-curvature="0" />
- </g>
- </g>
- </g>
-</svg>
diff --git a/files/opencs/scalable/startup/configure.svgz b/files/opencs/scalable/startup/configure.svgz
new file mode 100644
index 0000000000..1275ec53fa
--- /dev/null
+++ b/files/opencs/scalable/startup/configure.svgz
Binary files differ
diff --git a/files/opencs/scalable/startup/create-addon.svgz b/files/opencs/scalable/startup/create-addon.svgz
new file mode 100644
index 0000000000..75425667bd
--- /dev/null
+++ b/files/opencs/scalable/startup/create-addon.svgz
Binary files differ
diff --git a/files/opencs/scalable/startup/edit-content.svgz b/files/opencs/scalable/startup/edit-content.svgz
new file mode 100644
index 0000000000..049f1e8132
--- /dev/null
+++ b/files/opencs/scalable/startup/edit-content.svgz
Binary files differ
diff --git a/files/opencs/scalable/startup/new-game.svgz b/files/opencs/scalable/startup/new-game.svgz
new file mode 100644
index 0000000000..e815719111
--- /dev/null
+++ b/files/opencs/scalable/startup/new-game.svgz
Binary files differ
diff --git a/files/opencs/script.png b/files/opencs/script.png
new file mode 100644
index 0000000000..297da40210
--- /dev/null
+++ b/files/opencs/script.png
Binary files differ
diff --git a/files/opencs/skill.png b/files/opencs/skill.png
new file mode 100644
index 0000000000..418f4f35c2
--- /dev/null
+++ b/files/opencs/skill.png
Binary files differ
diff --git a/files/opencs/sound.png b/files/opencs/sound.png
new file mode 100644
index 0000000000..b072acf767
--- /dev/null
+++ b/files/opencs/sound.png
Binary files differ
diff --git a/files/opencs/soundgen.png b/files/opencs/soundgen.png
new file mode 100644
index 0000000000..222fc4c7fe
--- /dev/null
+++ b/files/opencs/soundgen.png
Binary files differ
diff --git a/files/opencs/spell.png b/files/opencs/spell.png
new file mode 100644
index 0000000000..69c8971805
--- /dev/null
+++ b/files/opencs/spell.png
Binary files differ
diff --git a/files/opencs/static.png b/files/opencs/static.png
index b53be12d9a..aedf2d30ee 100755..100644
--- a/files/opencs/static.png
+++ b/files/opencs/static.png
Binary files differ
diff --git a/files/opencs/weapon.png b/files/opencs/weapon.png
index 3d4b534661..3d4b534661 100755..100644
--- a/files/opencs/weapon.png
+++ b/files/opencs/weapon.png
Binary files differ
diff --git a/files/openmw.cfg.local b/files/openmw.cfg.local
index dd116e1080..d6ca2d5549 100644
--- a/files/openmw.cfg.local
+++ b/files/openmw.cfg.local
@@ -1,2 +1,5 @@
+data="?global?data"
+data="?mw?Data Files"
data=./data
+data-local="?user?data"
resources=./resources
diff --git a/files/ui/contentselector.ui b/files/ui/contentselector.ui
new file mode 100644
index 0000000000..b9b5ba5a03
--- /dev/null
+++ b/files/ui/contentselector.ui
@@ -0,0 +1,111 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>ContentSelector</class>
+ <widget class="QWidget" name="ContentSelector">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>518</width>
+ <height>436</height>
+ </rect>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Minimum" vsizetype="Minimum">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="contextMenuPolicy">
+ <enum>Qt::DefaultContextMenu</enum>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout">
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <item>
+ <widget class="QGroupBox" name="contentGroupBox">
+ <property name="title">
+ <string>Content</string>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout_2">
+ <property name="bottomMargin">
+ <number>3</number>
+ </property>
+ <item>
+ <widget class="ContentSelectorView::ComboBox" name="gameFileView">
+ <property name="editable">
+ <bool>false</bool>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QTableView" name="addonView">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="contextMenuPolicy">
+ <enum>Qt::DefaultContextMenu</enum>
+ </property>
+ <property name="acceptDrops">
+ <bool>true</bool>
+ </property>
+ <property name="editTriggers">
+ <set>QAbstractItemView::NoEditTriggers</set>
+ </property>
+ <property name="dragEnabled">
+ <bool>true</bool>
+ </property>
+ <property name="dragDropOverwriteMode">
+ <bool>false</bool>
+ </property>
+ <property name="dragDropMode">
+ <enum>QAbstractItemView::DragDrop</enum>
+ </property>
+ <property name="defaultDropAction">
+ <enum>Qt::MoveAction</enum>
+ </property>
+ <property name="alternatingRowColors">
+ <bool>true</bool>
+ </property>
+ <property name="selectionMode">
+ <enum>QAbstractItemView::SingleSelection</enum>
+ </property>
+ <property name="selectionBehavior">
+ <enum>QAbstractItemView::SelectRows</enum>
+ </property>
+ <property name="textElideMode">
+ <enum>Qt::ElideLeft</enum>
+ </property>
+ <property name="showGrid">
+ <bool>false</bool>
+ </property>
+ <attribute name="horizontalHeaderVisible">
+ <bool>false</bool>
+ </attribute>
+ <attribute name="horizontalHeaderStretchLastSection">
+ <bool>true</bool>
+ </attribute>
+ <attribute name="verticalHeaderVisible">
+ <bool>false</bool>
+ </attribute>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <customwidgets>
+ <customwidget>
+ <class>ContentSelectorView::ComboBox</class>
+ <extends>QComboBox</extends>
+ <header>components/contentselector/view/combobox.hpp</header>
+ </customwidget>
+ </customwidgets>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/files/ui/datafilespage.ui b/files/ui/datafilespage.ui
index 041a9576d0..eb5ebc61d6 100644
--- a/files/ui/datafilespage.ui
+++ b/files/ui/datafilespage.ui
@@ -7,108 +7,97 @@
<x>0</x>
<y>0</y>
<width>518</width>
- <height>304</height>
+ <height>108</height>
</rect>
</property>
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Minimum" vsizetype="Minimum">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="contextMenuPolicy">
+ <enum>Qt::DefaultContextMenu</enum>
+ </property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
- <layout class="QHBoxLayout" name="filterLayout">
- <item>
- <spacer name="horizontalSpacer">
- <property name="orientation">
- <enum>Qt::Horizontal</enum>
- </property>
- <property name="sizeHint" stdset="0">
- <size>
- <width>40</width>
- <height>20</height>
- </size>
- </property>
- </spacer>
- </item>
- <item>
- <widget class="QLabel" name="filterLabel">
- <property name="text">
- <string>Filter:</string>
- </property>
- </widget>
- </item>
- <item>
- <widget class="LineEdit" name="filterLineEdit"/>
- </item>
- </layout>
+ <widget class="QWidget" name="contentSelectorWidget" native="true"/>
</item>
<item>
- <widget class="QSplitter" name="splitter">
- <property name="sizePolicy">
- <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
- <horstretch>0</horstretch>
- <verstretch>0</verstretch>
- </sizepolicy>
+ <widget class="QGroupBox" name="profileGroupBox">
+ <property name="focusPolicy">
+ <enum>Qt::NoFocus</enum>
</property>
- <property name="orientation">
- <enum>Qt::Horizontal</enum>
+ <property name="title">
+ <string>Profile</string>
</property>
- <property name="childrenCollapsible">
+ <property name="flat">
<bool>false</bool>
</property>
- <widget class="QTableView" name="mastersTable"/>
- <widget class="QTableView" name="pluginsTable"/>
+ <layout class="QHBoxLayout" name="horizontalLayout_2">
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <property name="leftMargin">
+ <number>3</number>
+ </property>
+ <property name="topMargin">
+ <number>6</number>
+ </property>
+ <property name="rightMargin">
+ <number>0</number>
+ </property>
+ <property name="bottomMargin">
+ <number>6</number>
+ </property>
+ <item>
+ <widget class="ProfilesComboBox" name="profilesComboBox">
+ <property name="enabled">
+ <bool>true</bool>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Expanding" vsizetype="Fixed">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="toolTip">
+ <string>Select a profiile</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QToolButton" name="newProfileButton">
+ <property name="toolTip">
+ <string>New Profile</string>
+ </property>
+ <property name="text">
+ <string>&amp;New Profile</string>
+ </property>
+ <property name="autoRaise">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QToolButton" name="deleteProfileButton">
+ <property name="toolTip">
+ <string>Delete Profile</string>
+ </property>
+ <property name="text">
+ <string>Delete Profile</string>
+ </property>
+ <property name="shortcut">
+ <string>Ctrl+D</string>
+ </property>
+ <property name="autoRaise">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ </layout>
</widget>
</item>
- <item>
- <layout class="QHBoxLayout" name="horizontalLayout">
- <item>
- <widget class="QLabel" name="profileLabel">
- <property name="text">
- <string>Current Profile:</string>
- </property>
- </widget>
- </item>
- <item>
- <widget class="ProfilesComboBox" name="profilesComboBox">
- <property name="enabled">
- <bool>true</bool>
- </property>
- <property name="sizePolicy">
- <sizepolicy hsizetype="Expanding" vsizetype="Fixed">
- <horstretch>0</horstretch>
- <verstretch>0</verstretch>
- </sizepolicy>
- </property>
- </widget>
- </item>
- <item>
- <widget class="QToolButton" name="newProfileButton">
- <property name="toolTip">
- <string>New Profile</string>
- </property>
- <property name="text">
- <string>&amp;New Profile</string>
- </property>
- <property name="autoRaise">
- <bool>true</bool>
- </property>
- </widget>
- </item>
- <item>
- <widget class="QToolButton" name="deleteProfileButton">
- <property name="toolTip">
- <string>Delete Profile</string>
- </property>
- <property name="text">
- <string>Delete Profile</string>
- </property>
- <property name="shortcut">
- <string>Ctrl+D</string>
- </property>
- <property name="autoRaise">
- <bool>true</bool>
- </property>
- </widget>
- </item>
- </layout>
- </item>
</layout>
<action name="newProfileAction">
<property name="icon">
@@ -127,6 +116,9 @@
</property>
</action>
<action name="deleteProfileAction">
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
<property name="icon">
<iconset theme="edit-delete">
<normaloff/>
@@ -140,6 +132,9 @@
</property>
</action>
<action name="checkAction">
+ <property name="checkable">
+ <bool>true</bool>
+ </property>
<property name="text">
<string>Check Selection</string>
</property>
@@ -152,14 +147,9 @@
</widget>
<customwidgets>
<customwidget>
- <class>LineEdit</class>
- <extends>QLineEdit</extends>
- <header location="global">components/fileorderlist/utils/lineedit.hpp</header>
- </customwidget>
- <customwidget>
<class>ProfilesComboBox</class>
<extends>QComboBox</extends>
- <header location="global">components/fileorderlist/utils/profilescombobox.hpp</header>
+ <header>apps/launcher/utils/profilescombobox.hpp</header>
</customwidget>
</customwidgets>
<resources/>
diff --git a/files/ui/filedialog.ui b/files/ui/filedialog.ui
new file mode 100644
index 0000000000..b3af166dab
--- /dev/null
+++ b/files/ui/filedialog.ui
@@ -0,0 +1,73 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>FileDialog</class>
+ <widget class="QWidget" name="FileDialog">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>518</width>
+ <height>109</height>
+ </rect>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Minimum" vsizetype="Minimum">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="contextMenuPolicy">
+ <enum>Qt::DefaultContextMenu</enum>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout">
+ <item>
+ <widget class="QWidget" name="contentSelectorWidget" native="true"/>
+ </item>
+ <item>
+ <widget class="QGroupBox" name="projectGroupBox">
+ <property name="focusPolicy">
+ <enum>Qt::NoFocus</enum>
+ </property>
+ <property name="title">
+ <string>Project Name</string>
+ </property>
+ <property name="flat">
+ <bool>false</bool>
+ </property>
+ <layout class="QVBoxLayout" name="projectGroupBoxLayout">
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <property name="leftMargin">
+ <number>3</number>
+ </property>
+ <property name="topMargin">
+ <number>6</number>
+ </property>
+ <property name="rightMargin">
+ <number>0</number>
+ </property>
+ <property name="bottomMargin">
+ <number>6</number>
+ </property>
+ <item>
+ <widget class="QWidget" name="projectWidget" native="true">
+ <layout class="QVBoxLayout" name="verticalLayout_2">
+ <item>
+ <widget class="QDialogButtonBox" name="projectButtonBox">
+ <property name="standardButtons">
+ <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/libs/openengine/.gitignore b/libs/openengine/.gitignore
new file mode 100644
index 0000000000..23a5e931b8
--- /dev/null
+++ b/libs/openengine/.gitignore
@@ -0,0 +1,3 @@
+*~
+*.o
+*_test
diff --git a/libs/openengine/ogre/.gitignore b/libs/openengine/ogre/.gitignore
new file mode 100644
index 0000000000..3367afdbbf
--- /dev/null
+++ b/libs/openengine/ogre/.gitignore
@@ -0,0 +1 @@
+old
diff --git a/libs/openengine/ogre/lights.cpp b/libs/openengine/ogre/lights.cpp
index 52aca6a705..348057b846 100644
--- a/libs/openengine/ogre/lights.cpp
+++ b/libs/openengine/ogre/lights.cpp
@@ -1,20 +1,11 @@
#include "lights.hpp"
#include <OgreLight.h>
-#include <OgreMath.h>
+
namespace OEngine {
namespace Render {
-
-LightFunction::LightFunction(LightType type)
- : ControllerFunction<Ogre::Real>(true)
- , mType(type)
- , mPhase(Ogre::Math::RangeRandom(-500.0f, +500.0f))
- , mDirection(1.0f)
-{
-}
-
Ogre::Real LightFunction::pulseAmplitude(Ogre::Real time)
{
return std::sin(time);
@@ -97,13 +88,6 @@ Ogre::Real LightFunction::calculate(Ogre::Real value)
return brightness;
}
-
-LightValue::LightValue(Ogre::Light *light, const Ogre::ColourValue &color)
- : mTarget(light)
- , mColor(color)
-{
-}
-
Ogre::Real LightValue::getValue() const
{
return 0.0f;
diff --git a/libs/openengine/ogre/lights.hpp b/libs/openengine/ogre/lights.hpp
index c63f164255..61d09a0e65 100644
--- a/libs/openengine/ogre/lights.hpp
+++ b/libs/openengine/ogre/lights.hpp
@@ -3,6 +3,7 @@
#include <OgreController.h>
#include <OgreColourValue.h>
+#include <OgreMath.h>
/*
* Controller classes to handle pulsing and flicker lights
@@ -30,7 +31,14 @@ namespace Render {
static Ogre::Real flickerFrequency(Ogre::Real phase);
public:
- LightFunction(LightType type);
+ // MSVC needs the constructor for a class inheriting a template to be defined in header
+ LightFunction(LightType type)
+ : ControllerFunction<Ogre::Real>(true)
+ , mType(type)
+ , mPhase(Ogre::Math::RangeRandom(-500.0f, +500.0f))
+ , mDirection(1.0f)
+ {
+ }
virtual Ogre::Real calculate(Ogre::Real value);
};
@@ -40,7 +48,12 @@ namespace Render {
Ogre::ColourValue mColor;
public:
- LightValue(Ogre::Light *light, const Ogre::ColourValue &color);
+ // MSVC needs the constructor for a class inheriting a template to be defined in header
+ LightValue(Ogre::Light *light, const Ogre::ColourValue &color)
+ : mTarget(light)
+ , mColor(color)
+ {
+ }
virtual Ogre::Real getValue() const;
virtual void setValue(Ogre::Real value);
diff --git a/readme.txt b/readme.txt
index 7865f8dba2..afcfadea3d 100644
--- a/readme.txt
+++ b/readme.txt
@@ -3,7 +3,7 @@ OpenMW: A reimplementation of The Elder Scrolls III: Morrowind
OpenMW is an attempt at recreating the engine for the popular role-playing game
Morrowind by Bethesda Softworks. You need to own and install the original game for OpenMW to work.
-Version: 0.26.0
+Version: 0.27.0
License: GPL (see GPL3.txt for more information)
Website: http://www.openmw.org
@@ -82,6 +82,32 @@ Allowed options:
CHANGELOG
+0.27.0
+
+Bug #597: Assertion `dialogue->mId == id' failed in esmstore.cpp
+Bug #794: incorrect display of decimal numbers
+Bug #840: First-person sneaking camera height
+Bug #887: Ambient sounds playing while paused
+Bug #902: Problems with Polish character encoding
+Bug #907: Entering third person using the mousewheel is possible even if it's impossible using the key
+Bug #910: Some CDs not working correctly with Unshield installer
+Bug #917: Quick character creation plugin does not work
+Bug #918: Fatigue does not refill
+Bug #919: The PC falls dead in Beshara - OpenMW nightly Win64 (708CDE2)
+Feature #57: Acrobatics Skill
+Feature #462: Editor: Start Dialogue
+Feature #546: Modify ESX selector to handle new content file scheme
+Feature #588: Editor: Adjust name/path of edited content files
+Feature #644: Editor: Save
+Feature #710: Editor: Configure script compiler context
+Feature #790: God Mode
+Feature #881: Editor: Allow only one instance of OpenCS
+Feature #889: Editor: Record filtering
+Feature #895: Extinguish torches
+Feature #898: Breath meter enhancements
+Feature #901: Editor: Default record filter
+Feature #913: Merge --master and --plugin switches
+
0.26.0
Bug #274: Inconsistencies in the terrain