Merge branch 'master' of https://github.com/zinnschlag/openmw into magic

actorid
scrawl 11 years ago
commit 1773c70455

@ -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}")
@ -79,7 +79,6 @@ set(OENGINE_OGRE
${LIBDIR}/openengine/ogre/renderer.cpp
${LIBDIR}/openengine/ogre/fader.cpp
${LIBDIR}/openengine/ogre/lights.cpp
${LIBDIR}/openengine/ogre/particles.cpp
${LIBDIR}/openengine/ogre/selectionbuffer.cpp
${LIBDIR}/openengine/ogre/imagerotate.cpp
)
@ -319,6 +318,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
@ -380,7 +382,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)
@ -428,7 +429,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")
@ -455,13 +456,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")
@ -471,7 +481,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

@ -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.

@ -1,160 +0,0 @@
#Getting OpenMW Working on OS X
## Initial setup
First of all, clone OpenMW repo.
$ git clone github.com/zinnschlag/openmw
Or use your github url if you forked.
About dependencies: I prefer not to install them globally (i. e. in /usr/local/), so I'm installing them in directory in my home directory. If OpenMW sources is in $HOME/path/openmw, I'm using $HOME/path/libs/root as prefix for boost and other libs.
It's useful to create env var for lib install prefix:
$ export OMW_LIB_PREFIX=$HOME/path/libs/root`
Most of libs can be installed from [Homebrew][homebrew]. Only mpg123 needs to be installed from source (due to lack of universal compilation support). I think that some of libs can be installed from MacPorts or Fink too.
As OpenMW currently only supports i386 architecture on OS X, denendencies also should support it. Set some env vars in current terminal:
$ export CFLAGS="-arch i386"
$ export CXXFLAGS="-arch i386"
$ export LDFLAGS="-arch i386"
If you close your terminal, you should set env vars again before pcoceeding to next steps!
## Boost
Download [boost][boost] and install it with the following command:
$ cd /path/to/boost/source
$ ./bootstrap.sh --prefix=$OMW_LIB_PREFIX
$ ./bjam --build-dir=build --layout=versioned \
--toolset=darwin architecture=x86 address-model=32 \
--link-shared,static --prefix=$OMW_LIB_PREFIX install
Alternatively you can install boost with homebrew:
$ brew install boost --universal
I think MacPorts also should support universal build for boost.
## Ogre
Download [Ogre][] SDK (tested with 1.7.3), unpack it somewhere and move
`lib/Release/Ogre.framework` into `/Library/Frameworks`.
## OIS
Download patched [OIS][] and use the XCode project provided. Be sure to set your build architecture to
`i386`. Once it built, locate built OIS.framework with Xcode and move it to `/Library/Frameworks`.
## mpg123
Download [MPG 123][mpg123] and build it:
$ cd /path/to/mpg123/source
$ ./configure --prefix=$OMW_LIB_PREFIX --disable-debug \
--disable-dependency-tracking \
--with-optimization=4 \
--with-audio=dummy \
--with-default-audio=dummy \
--with-cpu=sse_alone \
$ make install
## libsndfile
Download [libsndfile][] and build it:
$ cd /path/to/libsndfile/source
$ ./configure --prefix=$OMW_LIB_PREFIX \
--disable-dependency-tracking
$ make install
or install with homebrew:
$ brew install libsndfile --universal
## Bullet
Download [Bullet][] and build it:
$ cd /path/to/bullet/source
$ mkdir build
$ cd build
$ cmake -DCMAKE_BUILD_TYPE=Release \
-DCMAKE_INSTALL_PREFIX=$OMW_LIB_PREFIX \
-DBUILD_EXTRAS=OFF \
-DBUILD_DEMOS=OFF \
-DCMAKE_OSX_ARCHITECTURES=i386 \
-DCMAKE_INSTALL_NAME_DIR=$OMW_LIB_RPEFIX/lib \
-G"Unix Makefiles" ../
$ make install
or install with homebrew:
$ brew install bullet --HEAD --universal
I prefer head because 2.79 has some issue which causes OpenMW to lag. Also you can edit formula and install 2.77, which is stable and haven't mentioned issue.
## Qt
Install [Qt][qt]. Qt SDK distributed by Nokia is not an option because it's 64 bit only, and OpenMW currently doesn't build for 64 bit on OS X. I'm installing it from Homebrew:
$ brew install qt --universal
## Run CMake
Generate the Makefile for OpenMW as follows and build OpenMW:
$ mkdir /path/to/openmw/build/dir
$ cd /path/to/open/build/dir
$ cmake \
-D CMAKE_OSX_ARCHITECTURES=i386 \
-D OGRE_SDK=/path/to/ogre/sdk \
-D BOOST_INCLUDEDIR=$OMW_LIB_PREFIX/include/boost-1_45 \
-D BOOST_LIBRARYDIR=$OMW_LIB_PREFIX/lib \
-D SNDFILE_INCLUDE_DIR=$OMW_LIB_PREFIX/include \
-D SNDFILE_LIBRARY=$OMW_LIB_PREFIX/lib/libsndfile.a \
-D MPG123_LIBRARY=$OMW_LIB_PREFIX/lib/libmpg123.a \
-D MPG123_INCLUDE_DIR=$OMW_LIB_PREFIX/include \
-D BULLET_DYNAMICS_LIBRARY=$OMW_LIB_PREFIX/lib/libBulletDynamics.a \
-D BULLET_COLLISION_LIBRARY=$OMW_LIB_PREFIX/lib/libBulletCollision.a \
-D BULLET_MATH_LIBRARY=$OMW_LIB_PREFIX/lib/libLinearMath.a \
-D BULLET_SOFTBODY_LIBRARY=$OMW_LIB_PREFIX/lib/libBulletSoftBody.a \
-D BULLET_INCLUDE_DIR=$OMW_LIB_PREFIX/include/bullet/ \
-G "Unix Makefiles" /path/to/openmw/source/dir
$ make
You can use `-G"Xcode"` if you prefer Xcode, or -G"Eclipse CDT4 - Unix Makefiles"
if you prefer Eclipse. You also can specify `-D CMAKE_BUILD_TYPE=Debug` for debug
build. As for CMake 2.8.7 and Xcode 4.3, Xcode generator is broken. Sadly Eclipse CDT also cannot import generated project at least on my machine.
If all libs installed via homebrew (excluding mpg123), then command would be even simplier:
$ cmake \
-D CMAKE_OSX_ARCHITECTURES="i386" \
-D OGRE_SDK=/path/to/ogre/sdk \
-D MPG123_LIBRARY=$OMW_LIB_PREFIX/lib/libmpg123.a \
-D MPG123_INCLUDE_DIR=$OMW_LIB_PREFIX/include \
-G "Unix Makefiles" /path/to/openmw/source/dir
$ make
Note for users with recent Xcode versions: you must explicitly specify what set of compilers do you use! If not, gcc will be used for C and Clang for C++. Just add this two -D's to command: `-D CMAKE_C_COMPILER=/usr/bin/clang` and `-D CMAKE_CXX_COMPILER=/usr/bin/clang`
Note for Xcode 4.3 users: you should specify full path to used SDK, because current CMake (2.8.7) couldn't find SDKs inside Xcode app bundle:
-D CMAKE_OSX_SYSROOT="/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.7.sdk"
# Run
From your build directory run:
$ OpenMW.app/Contents/MacOS/openmw
or:
$ open OpenMW.app
Enjoy!
[homebrew]: https://github.com/mxcl/homebrew
[boost]: http://www.boost.org
[Ogre]: http://www.ogre3d.org
[Bullet]: http://bulletphysics.org
[OIS]: https://github.com/corristo/ois-fork
[mpg123]: http://www.mpg123.de
[libsndfile]: http://www.mega-nerd.com/libsndfile
[official website]: http://openmw.com
[Will Thimbleby's Ogre Framework]: http://www.thimbleby.net/ogre/
[qt]: http://qt.nokia.com/

@ -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;

@ -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
)
@ -32,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)
@ -48,8 +51,11 @@ set(LAUNCHER_HEADER_MOC
playpage.hpp
textslotmsgbox.hpp
utils/checkablemessagebox.hpp
utils/textinputdialog.hpp
utils/checkablemessagebox.hpp
utils/profilescombobox.hpp
utils/lineedit.hpp
)
if(NOT WIN32)
@ -62,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})

@ -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);
}

@ -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

@ -10,14 +10,11 @@
#endif
#include <SDL.h>
#include <cstdlib>
#include <boost/math/common_factor.hpp>
#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 +30,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,15 +50,11 @@ 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;
logMgr->createLog((mCfgMgr.getLogPath().string() + "/launcherOgre.log"), true, false, false);
try
{
mOgre = new Ogre::Root("", "", "./launcherOgre.log");
mOgre = mOgreInit.init(mCfgMgr.getLogPath().string() + "/launcherOgre.log");
}
catch(Ogre::Exception &ex)
{
@ -78,40 +72,6 @@ bool GraphicsPage::setupOgre()
return false;
}
std::string pluginDir;
const char* pluginEnv = getenv("OPENMW_OGRE_PLUGIN_DIR");
if (pluginEnv)
pluginDir = pluginEnv;
else
{
#if OGRE_PLATFORM == OGRE_PLATFORM_WIN32
pluginDir = ".\\";
#endif
#if OGRE_PLATFORM == OGRE_PLATFORM_APPLE
pluginDir = OGRE_PLUGIN_DIR;
#endif
#if OGRE_PLATFORM == OGRE_PLATFORM_LINUX
pluginDir = OGRE_PLUGIN_DIR_REL;
#endif
}
QDir dir(QString::fromStdString(pluginDir));
pluginDir = dir.absolutePath().toStdString();
Files::loadOgrePlugin(pluginDir, "RenderSystem_GL", *mOgre);
Files::loadOgrePlugin(pluginDir, "RenderSystem_GL3Plus", *mOgre);
Files::loadOgrePlugin(pluginDir, "RenderSystem_Direct3D9", *mOgre);
#ifdef ENABLE_PLUGIN_GL
mGLPlugin = new Ogre::GLPlugin();
mOgre->installPlugin(mGLPlugin);
#endif
#ifdef ENABLE_PLUGIN_Direct3D9
mD3D9Plugin = new Ogre::D3D9Plugin();
mOgre->installPlugin(mD3D9Plugin);
#endif
// Get the available renderers and put them in the combobox
const Ogre::RenderSystemList &renderers = mOgre->getAvailableRenderers();
@ -156,7 +116,7 @@ bool GraphicsPage::setupOgre()
return true;
}
bool GraphicsPage::setupSDL()
bool Launcher::GraphicsPage::setupSDL()
{
int displays = SDL_GetNumVideoDisplays();
@ -179,7 +139,7 @@ bool GraphicsPage::setupSDL()
return true;
}
bool GraphicsPage::loadSettings()
bool Launcher::GraphicsPage::loadSettings()
{
if (!setupSDL())
return false;
@ -218,7 +178,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 +205,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 +238,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 +285,7 @@ QStringList GraphicsPage::getAvailableResolutions(int screen)
return result;
}
QRect GraphicsPage::getMaximumResolution()
QRect Launcher::GraphicsPage::getMaximumResolution()
{
QRect max;
int screens = QApplication::desktop()->screenCount();
@ -340,7 +300,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 +309,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 +317,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 +331,7 @@ void GraphicsPage::slotFullScreenChanged(int state)
}
}
void GraphicsPage::slotStandardToggled(bool checked)
void Launcher::GraphicsPage::slotStandardToggled(bool checked)
{
if (checked) {
resolutionComboBox->setEnabled(true);

@ -5,62 +5,53 @@
#include <OgreRoot.h>
#include <OgreRenderSystem.h>
//#include <OgreConfigFile.h>
//#include <OgreConfigDialog.h>
// Static plugin headers
#ifdef ENABLE_PLUGIN_GL
# include "OgreGLPlugin.h"
#endif
#ifdef ENABLE_PLUGIN_Direct3D9
# include "OgreD3D9Plugin.h"
#endif
#include <components/ogreinit/ogreinit.hpp>
#include "ui_graphicspage.h"
class GraphicsSettings;
namespace Files { struct ConfigurationManager; }
class GraphicsPage : public QWidget, private Ui::GraphicsPage
namespace Launcher
{
Q_OBJECT
class GraphicsSettings;
public:
GraphicsPage(Files::ConfigurationManager &cfg, GraphicsSettings &graphicsSettings, QWidget *parent = 0);
class GraphicsPage : public QWidget, private Ui::GraphicsPage
{
Q_OBJECT
void saveSettings();
bool loadSettings();
public:
GraphicsPage(Files::ConfigurationManager &cfg, GraphicsSettings &graphicsSettings, QWidget *parent = 0);
public slots:
void rendererChanged(const QString &renderer);
void screenChanged(int screen);
void saveSettings();
bool loadSettings();
private slots:
void slotFullScreenChanged(int state);
void slotStandardToggled(bool checked);
public slots:
void rendererChanged(const QString &renderer);
void screenChanged(int screen);
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
private slots:
void slotFullScreenChanged(int state);
void slotStandardToggled(bool checked);
Files::ConfigurationManager &mCfgMgr;
GraphicsSettings &mGraphicsSettings;
private:
OgreInit::OgreInit mOgreInit;
Ogre::Root *mOgre;
Ogre::RenderSystem *mSelectedRenderSystem;
Ogre::RenderSystem *mOpenGLRenderSystem;
Ogre::RenderSystem *mDirect3DRenderSystem;
QStringList getAvailableOptions(const QString &key, Ogre::RenderSystem *renderer);
QStringList getAvailableResolutions(int screen);
QRect getMaximumResolution();
Files::ConfigurationManager &mCfgMgr;
GraphicsSettings &mGraphicsSettings;
bool setupOgre();
bool setupSDL();
};
QStringList getAvailableOptions(const QString &key, Ogre::RenderSystem *renderer);
QStringList getAvailableResolutions(int screen);
QRect getMaximumResolution();
bool setupOgre();
bool setupSDL();
};
}
#endif

@ -10,8 +10,6 @@
#include <SDL.h>
#include "maindialog.hpp"
// SDL workaround
#include "graphicspage.hpp"
int main(int argc, char *argv[])
{
@ -49,7 +47,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 +59,3 @@ int main(int argc, char *argv[])
SDL_Quit();
return returnValue;
}

@ -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

@ -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

@ -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();
}

@ -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

@ -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;
}

@ -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

@ -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("([^/]+)/(.+)$");

@ -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

@ -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("([^/]+)/(.+)$");

@ -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

@ -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

@ -1,6 +1,6 @@
#include "textslotmsgbox.hpp"
void TextSlotMsgBox::setTextSlot(const QString& string)
void Launcher::TextSlotMsgBox::setTextSlot(const QString& string)
{
setText(string);
}

@ -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

@ -292,30 +292,30 @@ namespace
}
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;
@ -349,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());
@ -369,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";
@ -475,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");
@ -491,28 +491,28 @@ 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;

@ -7,50 +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);
bool extract();
void SetOutputPath(const std::string& path);
bool TribunalDone();
bool BloodmoonDone();
bool extract();
void Done();
bool TribunalDone();
bool BloodmoonDone();
std::string GetMWEsmPath();
void Done();
UnshieldThread();
std::string GetMWEsmPath();
private:
UnshieldThread();
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;
private:
bool mMorrowindDone;
bool mTribunalDone;
bool mBloodmoonDone;
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 mOutputPath;
boost::filesystem::path mMorrowindPath;
boost::filesystem::path mTribunalPath;
boost::filesystem::path mBloodmoonPath;
bool mMorrowindDone;
bool mTribunalDone;
bool mBloodmoonDone;
protected:
virtual void run();
boost::filesystem::path mOutputPath;
signals:
void signalGUI(QString);
void close();
};
protected:
virtual void run();
signals:
void signalGUI(QString);
void close();
};
}
#endif

@ -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));
}

@ -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

@ -1,10 +1,12 @@
#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");
@ -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 *)

@ -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

@ -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));
}

@ -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

@ -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));
}

@ -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

@ -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);
}
}

@ -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
@ -33,18 +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 newgame filewidget
adjusterwidget
viewmanager view operations operation subview startup filedialog newgame
filewidget adjusterwidget
)
@ -63,10 +63,14 @@ opencs_units (view/world
scenetoolmode
)
opencs_units (view/render
scenewidget
)
opencs_units_noqt (view/world
dialoguesubview subviews
enumdelegate vartypedelegate recordstatusdelegate idtypedelegate datadisplaydelegate
scripthighlighter idvalidator
scripthighlighter idvalidator dialoguecreator
)
@ -124,11 +128,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})
@ -158,3 +164,8 @@ target_link_libraries(opencs
${QT_LIBRARIES}
components
)
if(DPKG_PROGRAM)
INSTALL(TARGETS opencs RUNTIME DESTINATION games COMPONENT opencs)
endif()

@ -6,17 +6,21 @@
#include <QLocalSocket>
#include <QMessageBox>
#include <OgreRoot.h>
#include <OgreRenderWindow.h>
#include "model/doc/document.hpp"
#include "model/world/data.hpp"
CS::Editor::Editor() : mViewManager (mDocumentManager)
CS::Editor::Editor()
: mDocumentManager (mCfgMgr), mViewManager (mDocumentManager)
{
mIpcServerName = "org.openmw.OpenCS";
setupDataFiles();
mNewGame.setLocalData (mLocal);
mFileDialog.setLocalData (mLocal);
connect (&mViewManager, SIGNAL (newGameRequest ()), this, SLOT (createGame ()));
connect (&mViewManager, SIGNAL (newAddonRequest ()), this, SLOT (createAddon ()));
@ -28,23 +32,27 @@ CS::Editor::Editor() : mViewManager (mDocumentManager)
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&)));
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&)));
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);
@ -79,13 +87,16 @@ void CS::Editor::setupDataFiles()
}
// 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());
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);
}
@ -109,48 +120,39 @@ void CS::Editor::createGame()
void CS::Editor::createAddon()
{
mStartup.hide();
mFileDialog.newFile();
mFileDialog.showDialog (CSVDoc::ContentAction_New);
}
void CS::Editor::loadDocument()
{
mStartup.hide();
mFileDialog.openFile();
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());
}
/// \todo Get the save path from the file dialogue
CSMDoc::Document *document = mDocumentManager.addDocument (files, *files.rbegin(), 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());
/// \todo Get the save path from the file dialogue.
files.push_back(mFileDialog.filename().toStdString());
CSMDoc::Document *document = mDocumentManager.addDocument (files, *files.rbegin(), true);
CSMDoc::Document *document = mDocumentManager.addDocument (files, savePath, true);
mViewManager.addView (document);
mFileDialog.hide();
@ -212,6 +214,20 @@ int CS::Editor::run()
if (mLocal.empty())
return 1;
// TODO: setting
Ogre::Root::getSingleton().setRenderSystem(Ogre::Root::getSingleton().getRenderSystemByName("OpenGL Rendering Subsystem"));
Ogre::Root::getSingleton().initialise(false);
// Create a hidden background window to keep resources
Ogre::NameValuePairList params;
params.insert(std::make_pair("title", ""));
params.insert(std::make_pair("FSAA", "0"));
params.insert(std::make_pair("vsync", "false"));
params.insert(std::make_pair("hidden", "true"));
Ogre::RenderWindow* hiddenWindow = Ogre::Root::getSingleton().createRenderWindow("InactiveHidden", 1, 1, false, &params);
hiddenWindow->setActive(false);
mStartup.show();
QApplication::setQuitOnLastWindowClosed (true);

@ -26,15 +26,15 @@ namespace CS
{
Q_OBJECT
Files::ConfigurationManager mCfgMgr;
CSMSettings::UserSettings mUserSettings;
CSMDoc::DocumentManager mDocumentManager;
CSVDoc::ViewManager mViewManager;
CSVDoc::StartupDialogue mStartup;
CSVDoc::NewGameDialogue mNewGame;
CSVSettings::UserSettingsDialog mSettings;
FileDialog mFileDialog;
CSVDoc::FileDialog mFileDialog;
Files::ConfigurationManager mCfgMgr;
boost::filesystem::path mLocal;
void setupDataFiles();
@ -59,8 +59,8 @@ namespace CS
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();

@ -7,6 +7,8 @@
#include <QApplication>
#include <QIcon>
#include <components/ogreinit/ogreinit.hpp>
class Application : public QApplication
{
private:
@ -33,6 +35,12 @@ class Application : public QApplication
int main(int argc, char *argv[])
{
Q_INIT_RESOURCE (resources);
// TODO: Ogre startup shouldn't be here, but it currently has to:
// SceneWidget destructor will delete the created render window, which would be called _after_ Root has shut down :(
OgreInit::OgreInit ogreInit;
ogreInit.init("./opencsOgre.log"); // TODO log path?
Application mApplication (argc, argv);
mApplication.setWindowIcon (QIcon (":./opencs.png"));
@ -42,7 +50,7 @@ int main(int argc, char *argv[])
if(!editor.makeIPCServer())
{
editor.connectToIPCServer();
return 0;
// return 0;
}
return editor.run();

@ -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,11 +2144,86 @@ 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,
const boost::filesystem::path& savePath, bool new_)
: mSavePath (savePath), 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");
@ -2158,6 +2240,34 @@ CSMDoc::Document::Document (const std::vector<boost::filesystem::path>& files,
load (files.begin(), end, !new_);
}
if (new_)
{
mData.setDescription ("");
mData.setAuthor ("");
}
/// \todo un-outcomment the else, once loading an existing content file works properly again.
else
{
if (boost::filesystem::exists (mProjectPath))
{
getData().loadFile (mProjectPath, false, true);
}
else
{
boost::filesystem::path locCustomFiltersPath (configuration.getUserPath());
locCustomFiltersPath /= "defaultfilters";
if (boost::filesystem::exists(locCustomFiltersPath))
{
boost::filesystem::copy_file (locCustomFiltersPath, mProjectPath);
} else {
boost::filesystem::path filters(mResDir);
filters /= "defaultfilters";
boost::filesystem::copy_file(filters, mProjectPath);
}
getData().loadFile (mProjectPath, false, true);
}
}
addOptionalGmsts();
addOptionalGlobals();
@ -2166,9 +2276,10 @@ CSMDoc::Document::Document (const std::vector<boost::filesystem::path>& files,
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()
@ -2187,7 +2298,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,12 +2312,20 @@ const boost::filesystem::path& CSMDoc::Document::getSavePath() const
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()
@ -2218,44 +2337,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

@ -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
@ -32,16 +38,17 @@ namespace CSMDoc
private:
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,8 +71,7 @@ namespace CSMDoc
public:
Document (const std::vector<boost::filesystem::path>& files,
const boost::filesystem::path& savePath, 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();
@ -75,6 +81,10 @@ namespace CSMDoc
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();
CSMWorld::UniversalId verify();
@ -98,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:
@ -110,3 +119,4 @@ namespace CSMDoc
}
#endif

@ -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()
{
@ -17,7 +30,7 @@ CSMDoc::DocumentManager::~DocumentManager()
CSMDoc::Document *CSMDoc::DocumentManager::addDocument (const std::vector<boost::filesystem::path>& files, const boost::filesystem::path& savePath,
bool new_)
{
Document *document = new Document (files, savePath, 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);
}

@ -6,6 +6,11 @@
#include <boost/filesystem/path.hpp>
namespace Files
{
class ConfigurationManager;
}
namespace CSMDoc
{
class Document;
@ -13,18 +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,
const boost::filesystem::path& savePath, 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
@ -32,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;
};
}

@ -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);
}

@ -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();
};
}

@ -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));
}

@ -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

@ -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();
}
}

@ -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

@ -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;
}

@ -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

@ -0,0 +1,4 @@
#include "stage.hpp"
CSMDoc::Stage::~Stage() {}

@ -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.
};
}

@ -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;

@ -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;

@ -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;

@ -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;

@ -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;

@ -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;

@ -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;

@ -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;

@ -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;

@ -1,4 +0,0 @@
#include "stage.hpp"
CSMTools::Stage::~Stage() {}

@ -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);

@ -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:

@ -1,7 +0,0 @@
#include "verifier.hpp"
#include "../doc/state.hpp"
CSMTools::Verifier::Verifier() : Operation (CSMDoc::State_Verifying)
{}

@ -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

@ -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;
}

@ -4,6 +4,7 @@
#include <string>
#include "universalid.hpp"
#include "columns.hpp"
class QVariant;
@ -83,6 +84,13 @@ namespace CSMWorld
///< 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.
};
}

@ -43,7 +43,8 @@ namespace CSMWorld
Display_CreatureType,
Display_WeaponType,
Display_RecordState,
Display_RefRecordType
Display_RefRecordType,
Display_DialogueType
};
int mColumnId;

@ -1217,6 +1217,37 @@ namespace CSMWorld
}
};
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>
{
@ -1284,6 +1315,39 @@ namespace CSMWorld
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

@ -159,6 +159,8 @@ namespace CSMWorld
{ 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" },
@ -269,6 +271,11 @@ namespace
"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)
@ -283,6 +290,7 @@ namespace
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;
}

@ -152,6 +152,8 @@ namespace CSMWorld
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.

@ -44,6 +44,17 @@ void CSMWorld::Data::appendIds (std::vector<std::string>& ids, const CollectionB
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)
{
mGlobals.addColumn (new StringIdColumn<ESM::Global>);
@ -141,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));
@ -184,6 +203,7 @@ 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);
@ -196,6 +216,8 @@ 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);
@ -319,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;
@ -387,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;
@ -397,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())
@ -447,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
@ -469,10 +564,50 @@ 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;
@ -487,6 +622,8 @@ std::vector<std::string> CSMWorld::Data::getIds (bool listDeleted) const
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);

@ -20,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"
@ -48,12 +49,16 @@ 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&);
@ -66,6 +71,8 @@ namespace CSMWorld
bool listDeleted);
///< Append all IDs from collection to \a ids.
static int count (RecordBase::State state, const CollectionBase& collection);
public:
Data();
@ -116,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();
@ -141,8 +156,10 @@ 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;
@ -151,6 +168,17 @@ namespace CSMWorld
///
/// \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();

@ -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;
}
}

@ -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);
}

@ -539,3 +539,8 @@ std::vector<std::string> CSMWorld::RefIdCollection::getIds (bool listDeleted) co
{
return mData.getIds (listDeleted);
}
void CSMWorld::RefIdCollection::save (int index, ESM::ESMWriter& writer) const
{
mData.save (index, writer);
}

@ -9,6 +9,11 @@
#include "collectionbase.hpp"
#include "refiddata.hpp"
namespace ESM
{
class ESMWriter;
}
namespace CSMWorld
{
class RefIdAdapter;
@ -94,6 +99,8 @@ namespace CSMWorld
///< Return a sorted collection of all IDs
///
/// \param listDeleted include deleted record in the list
void save (int index, ESM::ESMWriter& writer) const;
};
}

@ -218,3 +218,16 @@ std::vector<std::string> CSMWorld::RefIdData::getIds (bool listDeleted) const
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);
}

@ -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:
@ -187,6 +217,8 @@ namespace CSMWorld
///< Return a sorted collection of all IDs
///
/// \param listDeleted include deleted record in the list
void save (int index, ESM::ESMWriter& writer) const;
};
}

@ -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 },
@ -54,6 +56,8 @@ namespace
{ 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" },

@ -87,6 +87,10 @@ namespace CSMWorld
Type_RegionMap,
Type_Filter,
Type_Filters,
Type_Topics,
Type_Topic,
Type_Journals,
Type_Journal,
Type_Scene
};

@ -11,7 +11,7 @@
#include <QStyle>
CSVDoc::AdjusterWidget::AdjusterWidget (QWidget *parent)
: QWidget (parent), mValid (false)
: QWidget (parent), mValid (false), mAction (ContentAction_Undefined)
{
QHBoxLayout *layout = new QHBoxLayout (this);
@ -30,6 +30,11 @@ CSVDoc::AdjusterWidget::AdjusterWidget (QWidget *parent)
setLayout (layout);
}
void CSVDoc::AdjusterWidget::setAction (ContentAction action)
{
mAction = action;
}
void CSVDoc::AdjusterWidget::setLocalData (const boost::filesystem::path& localData)
{
mLocalData = localData;
@ -43,41 +48,60 @@ boost::filesystem::path CSVDoc::AdjusterWidget::getPath() const
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;
if (name.isEmpty())
mValid = (!name.isEmpty());
if (!mValid)
{
mValid = false;
message = "No name.";
}
else
{
boost::filesystem::path path (name.toUtf8().data());
path.replace_extension (addon ? ".omwaddon" : ".omwgame");
bool isLegacyPath = (path.extension() == ".esm" ||
path.extension() == ".esp");
if (path.parent_path().string()==mLocalData.string())
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;
mValid = true;
}
//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.
path = mLocalData / path.filename();
if (isFilePathChanged)
path = mLocalData / path.filename();
message = QString::fromUtf8 (("Will be saved as: " + path.string()).c_str());
mResultPath = path;
mValid = true;
if (boost::filesystem::exists (path))
{
/// \todo add an user setting to make this an error.
message += "<p>But a file with the same name already exists. If you continue, it will be overwritten.";
message += "<p>A file with the same name already exists. If you continue, it will be overwritten.";
}
}
}
@ -88,4 +112,4 @@ void CSVDoc::AdjusterWidget::setName (const QString& name, bool addon)
pixmap (QSize (16, 16)));
emit stateChanged (mValid);
}
}

@ -9,21 +9,36 @@ 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.
@ -38,4 +53,4 @@ namespace CSVDoc
};
}
#endif
#endif

@ -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());
}

@ -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

@ -50,4 +50,9 @@ QString CSVDoc::FileWidget::getName() const
void CSVDoc::FileWidget::textChanged (const QString& text)
{
emit nameChanged (getName(), mAddon);
}
}
void CSVDoc::FileWidget::extensionLabelIsVisible(bool visible)
{
mType->setVisible(visible);
}

@ -27,6 +27,8 @@ namespace CSVDoc
QString getName() const;
void extensionLabelIsVisible(bool visible);
private slots:
void textChanged (const QString& text);

@ -6,7 +6,10 @@
#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;

@ -104,6 +104,17 @@ CSVDoc::StartupDialogue::StartupDialogue() : mWidth (0), mColumn (2)
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);
QRect scr = QApplication::desktop()->screenGeometry();

@ -163,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()
@ -412,6 +420,16 @@ 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);

@ -166,6 +166,10 @@ namespace CSVDoc
void addSceneSubView();
void addTopicsSubView();
void addJournalsSubView();
void toggleShowStatusBar (bool show);
};
}

@ -74,7 +74,8 @@ CSVDoc::ViewManager::ViewManager (CSMDoc::DocumentManager& documentManager)
{ 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_WeaponType, CSMWorld::Columns::ColumnId_WeaponType, false },
{ CSMWorld::ColumnBase::Display_DialogueType, CSMWorld::Columns::ColumnId_DialogueType, false }
};
for (std::size_t i=0; i<sizeof (sMapping)/sizeof (Mapping); ++i)

@ -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)));

@ -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,

@ -0,0 +1,128 @@
#include "scenewidget.hpp"
#include <QEvent>
#include <QResizeEvent>
#include <OgreRoot.h>
#include <OgreRenderWindow.h>
#include <OgreEntity.h>
namespace CSVRender
{
SceneWidget::SceneWidget(QWidget *parent)
: QWidget(parent)
, mWindow(NULL)
, mCamera(NULL)
, mSceneMgr(NULL)
{
setAttribute(Qt::WA_PaintOnScreen);
setAttribute(Qt::WA_NoSystemBackground);
mSceneMgr = Ogre::Root::getSingleton().createSceneManager(Ogre::ST_GENERIC);
// Throw in a random color just to make sure multiple scenes work
Ogre::Real r = Ogre::Math::RangeRandom(0, 1);
Ogre::Real g = Ogre::Math::RangeRandom(0, 1);
Ogre::Real b = Ogre::Math::RangeRandom(0, 1);
mSceneMgr->setAmbientLight(Ogre::ColourValue(r,g,b,1));
Ogre::Light* l = mSceneMgr->createLight();
l->setType (Ogre::Light::LT_DIRECTIONAL);
l->setDirection (Ogre::Vector3(-0.4, -0.7, 0.3));
l->setDiffuseColour (Ogre::ColourValue(0.7,0.7,0.7));
mCamera = mSceneMgr->createCamera("foo");
Ogre::Entity* ent = mSceneMgr->createEntity("cube", Ogre::SceneManager::PT_CUBE);
ent->setMaterialName("BaseWhite");
mSceneMgr->getRootSceneNode()->attachObject(ent);
mCamera->setPosition(300,300,300);
mCamera->lookAt(0,0,0);
mCamera->setNearClipDistance(0.1);
mCamera->setFarClipDistance(3000);
}
void SceneWidget::updateOgreWindow()
{
if (mWindow)
{
Ogre::Root::getSingleton().destroyRenderTarget(mWindow);
mWindow = NULL;
}
std::stringstream windowHandle;
windowHandle << this->winId();
std::stringstream windowTitle;
static int count=0;
windowTitle << ++count;
Ogre::NameValuePairList params;
params.insert(std::make_pair("externalWindowHandle", windowHandle.str()));
params.insert(std::make_pair("title", windowTitle.str()));
params.insert(std::make_pair("FSAA", "0")); // TODO setting
params.insert(std::make_pair("vsync", "false")); // TODO setting
mWindow = Ogre::Root::getSingleton().createRenderWindow(windowTitle.str(), this->width(), this->height(), false, &params);
mWindow->addViewport(mCamera)->setBackgroundColour(Ogre::ColourValue(0.3,0.3,0.3,1));
Ogre::Real aspectRatio = Ogre::Real(width()) / Ogre::Real(height());
mCamera->setAspectRatio(aspectRatio);
}
SceneWidget::~SceneWidget()
{
Ogre::Root::getSingleton().destroyRenderTarget(mWindow);
}
void SceneWidget::paintEvent(QPaintEvent* e)
{
if (!mWindow)
updateOgreWindow();
mWindow->update();
e->accept();
}
QPaintEngine* SceneWidget::paintEngine() const
{
// We don't want another paint engine to get in the way.
// So we return nothing.
return NULL;
}
void SceneWidget::resizeEvent(QResizeEvent *e)
{
if (!mWindow)
return;
const QSize &newSize = e->size();
// TODO: Fix Ogre to handle this more consistently (fixed in 1.9)
#if OGRE_PLATFORM == OGRE_PLATFORM_LINUX
mWindow->resize(newSize.width(), newSize.height());
#else
mWindow->windowMovedOrResized();
#endif
Ogre::Real aspectRatio = Ogre::Real(newSize.width()) / Ogre::Real(newSize.height());
mCamera->setAspectRatio(aspectRatio);
}
bool SceneWidget::event(QEvent *e)
{
if (e->type() == QEvent::WinIdChange)
{
// I haven't actually seen this happen yet.
if (mWindow)
updateOgreWindow();
}
return QWidget::event(e);
}
}

@ -0,0 +1,40 @@
#ifndef OPENCS_VIEW_SCENEWIDGET_H
#define OPENCS_VIEW_SCENEWIDGET_H
#include <QWidget>
namespace Ogre
{
class Camera;
class SceneManager;
class RenderWindow;
}
namespace CSVRender
{
class SceneWidget : public QWidget
{
Q_OBJECT
public:
SceneWidget(QWidget *parent);
virtual ~SceneWidget(void);
QPaintEngine* paintEngine() const;
private:
void paintEvent(QPaintEvent* e);
void resizeEvent(QResizeEvent* e);
bool event(QEvent* e);
void updateOgreWindow();
Ogre::Camera* mCamera;
Ogre::SceneManager* mSceneMgr;
Ogre::RenderWindow* mWindow;
};
}
#endif

@ -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);
}

@ -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

@ -9,6 +9,8 @@
#include "../filter/filterbox.hpp"
#include "../render/scenewidget.hpp"
#include "tablebottombox.hpp"
#include "creator.hpp"
#include "scenetoolbar.hpp"
@ -41,15 +43,10 @@ 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);
CSVRender::SceneWidget* sceneWidget = new CSVRender::SceneWidget(this);
layout2->addWidget (sceneWidget, 1);
layout->insertLayout (0, layout2, 1);
@ -79,4 +76,4 @@ void CSVWorld::SceneSubView::updateEditorSetting(const QString &settingName, con
void CSVWorld::SceneSubView::setStatusBar (bool show)
{
mBottom->setStatusBar (show);
}
}

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save