1
0
Fork 0
mirror of https://github.com/OpenMW/openmw.git synced 2025-02-05 20:15:33 +00:00
This commit is contained in:
Internecine 2014-12-28 22:42:55 +13:00
commit 7964d269ec
456 changed files with 12021 additions and 3736 deletions

View file

@ -19,7 +19,6 @@ after_script:
- if [ "${TRAVIS_OS_NAME}" = "linux" ]; then ./openmw_test_suite; fi - if [ "${TRAVIS_OS_NAME}" = "linux" ]; then ./openmw_test_suite; fi
notifications: notifications:
recipients: recipients:
- lgromanowski+travis.ci@gmail.com
- corrmage+travis-ci@gmail.com - corrmage+travis-ci@gmail.com
email: email:
on_success: change on_success: change

View file

@ -6,4 +6,4 @@ export CC=clang
brew tap openmw/openmw brew tap openmw/openmw
brew update brew update
brew unlink boost brew unlink boost
brew install cmake openmw-mygui openmw-bullet openmw-sdl2 openmw-ffmpeg pkg-config qt unshield brew install openmw-mygui openmw-bullet openmw-sdl2 openmw-ffmpeg qt unshield

View file

@ -12,7 +12,7 @@ set(CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake/)
message(STATUS "Configuring OpenMW...") message(STATUS "Configuring OpenMW...")
set(OPENMW_VERSION_MAJOR 0) set(OPENMW_VERSION_MAJOR 0)
set(OPENMW_VERSION_MINOR 33) set(OPENMW_VERSION_MINOR 34)
set(OPENMW_VERSION_RELEASE 0) set(OPENMW_VERSION_RELEASE 0)
set(OPENMW_VERSION_COMMITHASH "") set(OPENMW_VERSION_COMMITHASH "")
@ -25,24 +25,28 @@ if(EXISTS ${PROJECT_SOURCE_DIR}/.git)
find_package(Git) find_package(Git)
if(GIT_FOUND) if(GIT_FOUND)
include(GetGitRevisionDescription) execute_process (
get_git_tag_revision(TAGHASH --tags --max-count=1) COMMAND "${GIT_EXECUTABLE}" rev-list --tags --max-count=1
get_git_head_revision(REFSPEC COMMITHASH) WORKING_DIRECTORY "${PROJECT_SOURCE_DIR}"
git_describe(VERSION --tags ${TAGHASH}) RESULT_VARIABLE EXITCODE1
OUTPUT_VARIABLE TAGHASH
OUTPUT_STRIP_TRAILING_WHITESPACE)
string(REGEX MATCH "^openmw-[^0-9]*[0-9]+\\.[0-9]+\\.[0-9]+.*" MATCH "${VERSION}") execute_process (
if(MATCH) COMMAND "${GIT_EXECUTABLE}" rev-parse HEAD
string(REGEX REPLACE "^openmw-([0-9]+)\\..*" "\\1" GIT_VERSION_MAJOR "${VERSION}") WORKING_DIRECTORY "${PROJECT_SOURCE_DIR}"
string(REGEX REPLACE "^openmw-[0-9]+\\.([0-9]+).*" "\\1" GIT_VERSION_MINOR "${VERSION}") RESULT_VARIABLE EXITCODE2
string(REGEX REPLACE "^openmw-[0-9]+\\.[0-9]+\\.([0-9]+).*" "\\1" GIT_VERSION_RELEASE "${VERSION}") OUTPUT_VARIABLE COMMITHASH
OUTPUT_STRIP_TRAILING_WHITESPACE)
string (COMPARE EQUAL "${EXITCODE1}:${EXITCODE2}" "0:0" SUCCESS)
if (SUCCESS)
set(OPENMW_VERSION_COMMITHASH "${COMMITHASH}") set(OPENMW_VERSION_COMMITHASH "${COMMITHASH}")
set(OPENMW_VERSION_TAGHASH "${TAGHASH}") set(OPENMW_VERSION_TAGHASH "${TAGHASH}")
message(STATUS "OpenMW version ${OPENMW_VERSION}") message(STATUS "OpenMW version ${OPENMW_VERSION}")
else(MATCH) else (SUCCESS)
message(WARNING "Failed to get valid version information from Git") message(WARNING "Failed to get valid version information from Git")
endif(MATCH) endif (SUCCESS)
else(GIT_FOUND) else(GIT_FOUND)
message(WARNING "Git executable not found") message(WARNING "Git executable not found")
endif(GIT_FOUND) endif(GIT_FOUND)
@ -75,6 +79,7 @@ option(BUILD_ESMTOOL "build ESM inspector" ON)
option(BUILD_LAUNCHER "build Launcher" ON) option(BUILD_LAUNCHER "build Launcher" ON)
option(BUILD_MWINIIMPORTER "build MWiniImporter" ON) option(BUILD_MWINIIMPORTER "build MWiniImporter" ON)
option(BUILD_OPENCS "build OpenMW Construction Set" ON) option(BUILD_OPENCS "build OpenMW Construction Set" ON)
option(BUILD_WIZARD "build Installation Wizard" ON)
option(BUILD_WITH_CODE_COVERAGE "Enable code coverage with gconv" OFF) option(BUILD_WITH_CODE_COVERAGE "Enable code coverage with gconv" OFF)
option(BUILD_UNITTESTS "Enable Unittests with Google C++ Unittest and GMock frameworks" OFF) option(BUILD_UNITTESTS "Enable Unittests with Google C++ Unittest and GMock frameworks" OFF)
option(BUILD_NIFTEST "build nif file tester" OFF) option(BUILD_NIFTEST "build nif file tester" OFF)
@ -433,6 +438,9 @@ IF(NOT WIN32 AND NOT APPLE)
IF(BUILD_NIFTEST) IF(BUILD_NIFTEST)
INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/niftest" DESTINATION "${BINDIR}" ) INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/niftest" DESTINATION "${BINDIR}" )
ENDIF(BUILD_NIFTEST) ENDIF(BUILD_NIFTEST)
IF(BUILD_WIZARD)
INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/openmw-wizard" DESTINATION "${BINDIR}" )
ENDIF(BUILD_WIZARD)
if(BUILD_MYGUI_PLUGIN) if(BUILD_MYGUI_PLUGIN)
INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/Plugin_MyGUI_OpenMW_Resources.so" DESTINATION "${LIBDIR}" ) INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/Plugin_MyGUI_OpenMW_Resources.so" DESTINATION "${LIBDIR}" )
ENDIF(BUILD_MYGUI_PLUGIN) ENDIF(BUILD_MYGUI_PLUGIN)
@ -485,6 +493,9 @@ if(WIN32)
INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/Release/opencs.exe" DESTINATION ".") INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/Release/opencs.exe" DESTINATION ".")
INSTALL(FILES "${OpenMW_BINARY_DIR}/opencs.ini" DESTINATION ".") INSTALL(FILES "${OpenMW_BINARY_DIR}/opencs.ini" DESTINATION ".")
ENDIF(BUILD_OPENCS) ENDIF(BUILD_OPENCS)
IF(BUILD_WIZARD)
INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/Release/openmw-wizard.exe" DESTINATION ".")
ENDIF(BUILD_WIZARD)
if(BUILD_MYGUI_PLUGIN) if(BUILD_MYGUI_PLUGIN)
INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/Release/Plugin_MyGUI_OpenMW_Resources.dll" DESTINATION ".") INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/Release/Plugin_MyGUI_OpenMW_Resources.dll" DESTINATION ".")
ENDIF(BUILD_MYGUI_PLUGIN) ENDIF(BUILD_MYGUI_PLUGIN)
@ -505,6 +516,9 @@ if(WIN32)
IF(BUILD_OPENCS) IF(BUILD_OPENCS)
SET(CPACK_PACKAGE_EXECUTABLES "${CPACK_PACKAGE_EXECUTABLES};opencs;OpenMW Construction Set") SET(CPACK_PACKAGE_EXECUTABLES "${CPACK_PACKAGE_EXECUTABLES};opencs;OpenMW Construction Set")
ENDIF(BUILD_OPENCS) ENDIF(BUILD_OPENCS)
IF(BUILD_WIZARD)
SET(CPACK_PACKAGE_EXECUTABLES "${CPACK_PACKAGE_EXECUTABLES};openmw-wizard;OpenMW Wizard")
ENDIF(BUILD_WIZARD)
SET(CPACK_NSIS_CREATE_ICONS_EXTRA "CreateShortCut '\$SMPROGRAMS\\\\$STARTMENU_FOLDER\\\\Readme.lnk' '\$INSTDIR\\\\readme.txt'") SET(CPACK_NSIS_CREATE_ICONS_EXTRA "CreateShortCut '\$SMPROGRAMS\\\\$STARTMENU_FOLDER\\\\Readme.lnk' '\$INSTDIR\\\\readme.txt'")
SET(CPACK_NSIS_DELETE_ICONS_EXTRA " SET(CPACK_NSIS_DELETE_ICONS_EXTRA "
!insertmacro MUI_STARTMENU_GETFOLDER Application $MUI_TEMP !insertmacro MUI_STARTMENU_GETFOLDER Application $MUI_TEMP
@ -578,13 +592,6 @@ if (BUILD_ESMTOOL)
endif() endif()
if (BUILD_LAUNCHER) if (BUILD_LAUNCHER)
if(NOT WIN32)
find_package(LIBUNSHIELD REQUIRED)
if(NOT LIBUNSHIELD_FOUND)
message(SEND_ERROR "Failed to find libunshield")
endif(NOT LIBUNSHIELD_FOUND)
endif(NOT WIN32)
add_subdirectory( apps/launcher ) add_subdirectory( apps/launcher )
endif() endif()
@ -596,6 +603,10 @@ if (BUILD_OPENCS)
add_subdirectory (apps/opencs) add_subdirectory (apps/opencs)
endif() endif()
if (BUILD_WIZARD)
add_subdirectory(apps/wizard)
endif()
# UnitTests # UnitTests
if (BUILD_UNITTESTS) if (BUILD_UNITTESTS)
add_subdirectory( apps/openmw_test_suite ) add_subdirectory( apps/openmw_test_suite )
@ -698,6 +709,9 @@ if (WIN32)
if (BUILD_ESMTOOL) if (BUILD_ESMTOOL)
set_target_properties(esmtool PROPERTIES COMPILE_FLAGS "${WARNINGS} ${MT_BUILD}") set_target_properties(esmtool PROPERTIES COMPILE_FLAGS "${WARNINGS} ${MT_BUILD}")
endif (BUILD_ESMTOOL) endif (BUILD_ESMTOOL)
if (BUILD_WIZARD)
set_target_properties(openmw-wizard PROPERTIES COMPILE_FLAGS ${WARNINGS})
endif (BUILD_WIZARD)
if (BUILD_OPENCS) if (BUILD_OPENCS)
# QT triggers an informational warning that the object layout may differ when compiled with /vd2 # QT triggers an informational warning that the object layout may differ when compiled with /vd2
set(OPENCS_WARNINGS "${WARNINGS} ${MT_BUILD} /wd4435") set(OPENCS_WARNINGS "${WARNINGS} ${MT_BUILD} /wd4435")

View file

@ -51,7 +51,7 @@ bool parseOptions (int argc, char** argv, Arguments &info)
("help,h", "print help message.") ("help,h", "print help message.")
("version,v", "print version information and quit.") ("version,v", "print version information and quit.")
("long,l", "Include extra information in archive listing.") ("long,l", "Include extra information in archive listing.")
("full-path,f", "Create diretory hierarchy on file extraction " ("full-path,f", "Create directory hierarchy on file extraction "
"(always true for extractall).") "(always true for extractall).")
; ;

View file

@ -5,21 +5,16 @@ set(LAUNCHER
maindialog.cpp maindialog.cpp
playpage.cpp playpage.cpp
textslotmsgbox.cpp textslotmsgbox.cpp
settingspage.cpp
settings/gamesettings.cpp
settings/graphicssettings.cpp settings/graphicssettings.cpp
settings/launchersettings.cpp
utils/checkablemessagebox.cpp
utils/profilescombobox.cpp utils/profilescombobox.cpp
utils/textinputdialog.cpp utils/textinputdialog.cpp
utils/lineedit.cpp utils/lineedit.cpp
${CMAKE_SOURCE_DIR}/files/windows/launcher.rc ${CMAKE_SOURCE_DIR}/files/windows/launcher.rc
) )
if(NOT WIN32)
LIST(APPEND LAUNCHER unshieldthread.cpp)
endif(NOT WIN32)
set(LAUNCHER_HEADER set(LAUNCHER_HEADER
datafilespage.hpp datafilespage.hpp
@ -27,21 +22,14 @@ set(LAUNCHER_HEADER
maindialog.hpp maindialog.hpp
playpage.hpp playpage.hpp
textslotmsgbox.hpp textslotmsgbox.hpp
settingspage.hpp
settings/gamesettings.hpp
settings/graphicssettings.hpp settings/graphicssettings.hpp
settings/launchersettings.hpp
settings/settingsbase.hpp
utils/checkablemessagebox.hpp
utils/profilescombobox.hpp utils/profilescombobox.hpp
utils/textinputdialog.hpp utils/textinputdialog.hpp
utils/lineedit.hpp utils/lineedit.hpp
) )
if(NOT WIN32)
LIST(APPEND LAUNCHER_HEADER unshieldthread.hpp)
endif(NOT WIN32)
# Headers that must be pre-processed # Headers that must be pre-processed
set(LAUNCHER_HEADER_MOC set(LAUNCHER_HEADER_MOC
@ -50,25 +38,21 @@ set(LAUNCHER_HEADER_MOC
maindialog.hpp maindialog.hpp
playpage.hpp playpage.hpp
textslotmsgbox.hpp textslotmsgbox.hpp
settingspage.hpp
utils/textinputdialog.hpp utils/textinputdialog.hpp
utils/checkablemessagebox.hpp
utils/profilescombobox.hpp utils/profilescombobox.hpp
utils/lineedit.hpp utils/lineedit.hpp
) )
if(NOT WIN32)
LIST(APPEND LAUNCHER_HEADER_MOC unshieldthread.hpp)
endif(NOT WIN32)
set(LAUNCHER_UI set(LAUNCHER_UI
${CMAKE_SOURCE_DIR}/files/ui/datafilespage.ui ${CMAKE_SOURCE_DIR}/files/ui/datafilespage.ui
${CMAKE_SOURCE_DIR}/files/ui/graphicspage.ui ${CMAKE_SOURCE_DIR}/files/ui/graphicspage.ui
${CMAKE_SOURCE_DIR}/files/ui/mainwindow.ui ${CMAKE_SOURCE_DIR}/files/ui/mainwindow.ui
${CMAKE_SOURCE_DIR}/files/ui/playpage.ui ${CMAKE_SOURCE_DIR}/files/ui/playpage.ui
${CMAKE_SOURCE_DIR}/files/ui/contentselector.ui ${CMAKE_SOURCE_DIR}/files/ui/contentselector.ui
${CMAKE_SOURCE_DIR}/files/ui/settingspage.ui
) )
source_group(launcher FILES ${LAUNCHER} ${LAUNCHER_HEADER}) source_group(launcher FILES ${LAUNCHER} ${LAUNCHER_HEADER})
@ -111,12 +95,6 @@ target_link_libraries(omwlauncher
${QT_LIBRARIES} ${QT_LIBRARIES}
components components
) )
if(NOT WIN32)
target_link_libraries(omwlauncher
${LIBUNSHIELD_LIBRARY}
)
endif(NOT WIN32)
if (BUILD_WITH_CODE_COVERAGE) if (BUILD_WITH_CODE_COVERAGE)

View file

@ -1,5 +1,7 @@
#include "datafilespage.hpp" #include "datafilespage.hpp"
#include <QDebug>
#include <QPushButton> #include <QPushButton>
#include <QMessageBox> #include <QMessageBox>
#include <QCheckBox> #include <QCheckBox>
@ -9,18 +11,16 @@
#include <components/files/configurationmanager.hpp> #include <components/files/configurationmanager.hpp>
#include <components/contentselector/model/esmfile.hpp> #include <components/contentselector/model/esmfile.hpp>
#include <components/contentselector/model/naturalsort.hpp> #include <components/contentselector/model/naturalsort.hpp>
#include <components/contentselector/view/contentselector.hpp>
#include <components/config/gamesettings.hpp>
#include <components/config/launchersettings.hpp>
#include "utils/textinputdialog.hpp" #include "utils/textinputdialog.hpp"
#include "utils/profilescombobox.hpp" #include "utils/profilescombobox.hpp"
#include "settings/gamesettings.hpp" Launcher::DataFilesPage::DataFilesPage(Files::ConfigurationManager &cfg, Config::GameSettings &gameSettings, Config::LauncherSettings &launcherSettings, QWidget *parent)
#include "settings/launchersettings.hpp"
#include "components/contentselector/view/contentselector.hpp"
Launcher::DataFilesPage::DataFilesPage(Files::ConfigurationManager &cfg, GameSettings &gameSettings, LauncherSettings &launcherSettings, QWidget *parent)
: mCfgMgr(cfg) : mCfgMgr(cfg)
, mGameSettings(gameSettings) , mGameSettings(gameSettings)
, mLauncherSettings(launcherSettings) , mLauncherSettings(launcherSettings)
@ -30,20 +30,71 @@ Launcher::DataFilesPage::DataFilesPage(Files::ConfigurationManager &cfg, GameSet
setObjectName ("DataFilesPage"); setObjectName ("DataFilesPage");
mSelector = new ContentSelectorView::ContentSelector (ui.contentSelectorWidget); mSelector = new ContentSelectorView::ContentSelector (ui.contentSelectorWidget);
mProfileDialog = new TextInputDialog(tr("New Profile"), tr("Profile name:"), this);
connect(mProfileDialog->lineEdit(), SIGNAL(textChanged(QString)),
this, SLOT(updateOkButton(QString)));
buildView(); buildView();
setupDataFiles(); loadSettings();
} }
void Launcher::DataFilesPage::loadSettings() void Launcher::DataFilesPage::buildView()
{
ui.verticalLayout->insertWidget (0, mSelector->uiWidget());
//tool buttons
ui.newProfileButton->setToolTip ("Create a new profile");
ui.deleteProfileButton->setToolTip ("Delete an existing profile");
//combo box
ui.profilesComboBox->addItem ("Default");
ui.profilesComboBox->setPlaceholderText (QString("Select a profile..."));
ui.profilesComboBox->setCurrentIndex(ui.profilesComboBox->findText(QLatin1String("Default")));
// Add the actions to the toolbuttons
ui.newProfileButton->setDefaultAction (ui.newProfileAction);
ui.deleteProfileButton->setDefaultAction (ui.deleteProfileAction);
//establish connections
connect (ui.profilesComboBox, SIGNAL (currentIndexChanged(int)),
this, SLOT (slotProfileChanged(int)));
connect (ui.profilesComboBox, SIGNAL (profileRenamed(QString, QString)),
this, SLOT (slotProfileRenamed(QString, QString)));
connect (ui.profilesComboBox, SIGNAL (signalProfileChanged(QString, QString)),
this, SLOT (slotProfileChangedByUser(QString, QString)));
}
bool Launcher::DataFilesPage::loadSettings()
{ {
QStringList paths = mGameSettings.getDataDirs(); QStringList paths = mGameSettings.getDataDirs();
foreach (const QString &path, paths)
mSelector->addFiles(path);
mDataLocal = mGameSettings.getDataLocal();
if (!mDataLocal.isEmpty())
mSelector->addFiles(mDataLocal);
paths.insert (0, mDataLocal); paths.insert (0, mDataLocal);
PathIterator pathIterator (paths); PathIterator pathIterator (paths);
QString profileName = ui.profilesComboBox->currentText(); QStringList profiles = mLauncherSettings.subKeys(QString("Profiles/"));
QString currentProfile = mLauncherSettings.getSettings().value("Profiles/currentprofile");
QStringList files = mLauncherSettings.values(QString("Profiles/") + profileName, Qt::MatchExactly); qDebug() << "current profile is: " << currentProfile;
foreach (const QString &item, profiles)
addProfile (item, false);
// Hack: also add the current profile
if (!currentProfile.isEmpty())
addProfile(currentProfile, true);
QStringList files = mLauncherSettings.values(QString("Profiles/") + currentProfile + QString("/content"), Qt::MatchExactly);
QStringList filepaths; QStringList filepaths;
foreach (const QString &file, files) foreach (const QString &file, files)
@ -55,6 +106,8 @@ void Launcher::DataFilesPage::loadSettings()
} }
mSelector->setProfileContent (filepaths); mSelector->setProfileContent (filepaths);
return true;
} }
void Launcher::DataFilesPage::saveSettings(const QString &profile) void Launcher::DataFilesPage::saveSettings(const QString &profile)
@ -75,42 +128,16 @@ void Launcher::DataFilesPage::saveSettings(const QString &profile)
mLauncherSettings.setValue(QString("Profiles/currentprofile"), ui.profilesComboBox->currentText()); mLauncherSettings.setValue(QString("Profiles/currentprofile"), ui.profilesComboBox->currentText());
foreach(const ContentSelectorModel::EsmFile *item, items) { foreach(const ContentSelectorModel::EsmFile *item, items) {
mLauncherSettings.setMultiValue(QString("Profiles/") + profileName, item->fileName()); mLauncherSettings.setMultiValue(QString("Profiles/") + profileName + QString("/content"), item->fileName());
mGameSettings.setMultiValue(QString("content"), item->fileName()); mGameSettings.setMultiValue(QString("content"), item->fileName());
} }
} }
void Launcher::DataFilesPage::buildView()
{
ui.verticalLayout->insertWidget (0, mSelector->uiWidget());
//tool buttons
ui.newProfileButton->setToolTip ("Create a new profile");
ui.deleteProfileButton->setToolTip ("Delete an existing profile");
//combo box
ui.profilesComboBox->addItem ("Default");
ui.profilesComboBox->setPlaceholderText (QString("Select a profile..."));
// Add the actions to the toolbuttons
ui.newProfileButton->setDefaultAction (ui.newProfileAction);
ui.deleteProfileButton->setDefaultAction (ui.deleteProfileAction);
//establish connections
connect (ui.profilesComboBox, SIGNAL (currentIndexChanged(int)),
this, SLOT (slotProfileChanged(int)));
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 Launcher::DataFilesPage::removeProfile(const QString &profile) void Launcher::DataFilesPage::removeProfile(const QString &profile)
{ {
mLauncherSettings.remove(QString("Profiles/") + profile); mLauncherSettings.remove(QString("Profiles/") + profile);
mLauncherSettings.remove(QString("Profiles/") + profile + QString("/content"));
} }
QAbstractItemModel *Launcher::DataFilesPage::profilesModel() const QAbstractItemModel *Launcher::DataFilesPage::profilesModel() const
@ -127,9 +154,11 @@ void Launcher::DataFilesPage::setProfile(int index, bool savePrevious)
{ {
if (index >= -1 && index < ui.profilesComboBox->count()) if (index >= -1 && index < ui.profilesComboBox->count())
{ {
QString previous = ui.profilesComboBox->itemText(ui.profilesComboBox->currentIndex()); QString previous = mPreviousProfile;
QString current = ui.profilesComboBox->itemText(index); QString current = ui.profilesComboBox->itemText(index);
mPreviousProfile = current;
setProfile (previous, current, savePrevious); setProfile (previous, current, savePrevious);
} }
} }
@ -177,62 +206,29 @@ void Launcher::DataFilesPage::slotProfileRenamed(const QString &previous, const
void Launcher::DataFilesPage::slotProfileChanged(int index) void Launcher::DataFilesPage::slotProfileChanged(int index)
{ {
// in case the event was triggered externally
if (ui.profilesComboBox->currentIndex() != index)
ui.profilesComboBox->setCurrentIndex(index);
setProfile (index, true); setProfile (index, true);
} }
void Launcher::DataFilesPage::setupDataFiles()
{
QStringList paths = mGameSettings.getDataDirs();
foreach (const QString &path, paths)
mSelector->addFiles(path);
mDataLocal = mGameSettings.getDataLocal();
if (!mDataLocal.isEmpty())
mSelector->addFiles(mDataLocal);
QStringList profiles;
QString currentProfile = mLauncherSettings.getSettings().value("Profiles/currentprofile");
foreach (QString key, mLauncherSettings.getSettings().keys())
{
if (key.contains("Profiles/"))
{
QString profile = key.mid (9);
if (profile != "currentprofile")
{
if (!profiles.contains(profile))
profiles << profile;
}
}
}
foreach (const QString &item, profiles)
addProfile (item, false);
setProfile (ui.profilesComboBox->findText(currentProfile), false);
loadSettings();
}
void Launcher::DataFilesPage::on_newProfileAction_triggered() void Launcher::DataFilesPage::on_newProfileAction_triggered()
{ {
TextInputDialog newDialog (tr("New Profile"), tr("Profile name:"), this); if (mProfileDialog->exec() != QDialog::Accepted)
if (newDialog.exec() != QDialog::Accepted)
return; return;
QString profile = newDialog.getText(); QString profile = mProfileDialog->lineEdit()->text();
if (profile.isEmpty()) if (profile.isEmpty())
return; return;
saveSettings(); saveSettings();
mSelector->clearCheckStates(); mLauncherSettings.setValue(QString("Profiles/currentprofile"), profile);
addProfile(profile, true); addProfile(profile, true);
mSelector->clearCheckStates();
mSelector->setGameFile(); mSelector->setGameFile();
@ -246,9 +242,7 @@ void Launcher::DataFilesPage::addProfile (const QString &profile, bool setAsCurr
if (profile.isEmpty()) if (profile.isEmpty())
return; return;
if (ui.profilesComboBox->findText (profile) != -1) if (ui.profilesComboBox->findText (profile) == -1)
return;
ui.profilesComboBox->addItem (profile); ui.profilesComboBox->addItem (profile);
if (setAsCurrent) if (setAsCurrent)
@ -265,10 +259,12 @@ void Launcher::DataFilesPage::on_deleteProfileAction_triggered()
if (!showDeleteMessageBox (profile)) if (!showDeleteMessageBox (profile))
return; return;
// Remove the profile from the combobox // this should work since the Default profile can't be deleted and is always index 0
ui.profilesComboBox->removeItem (ui.profilesComboBox->findText (profile)); int next = ui.profilesComboBox->currentIndex()-1;
ui.profilesComboBox->setCurrentIndex(next);
removeProfile(profile); removeProfile(profile);
ui.profilesComboBox->removeItem(ui.profilesComboBox->findText(profile));
saveSettings(); saveSettings();
@ -277,6 +273,19 @@ void Launcher::DataFilesPage::on_deleteProfileAction_triggered()
checkForDefaultProfile(); checkForDefaultProfile();
} }
void Launcher::DataFilesPage::updateOkButton(const QString &text)
{
// We do this here because we need the profiles combobox text
if (text.isEmpty()) {
mProfileDialog->setOkButtonEnabled(false);
return;
}
(ui.profilesComboBox->findText(text) == -1)
? mProfileDialog->setOkButtonEnabled(true)
: mProfileDialog->setOkButtonEnabled(false);
}
void Launcher::DataFilesPage::checkForDefaultProfile() void Launcher::DataFilesPage::checkForDefaultProfile()
{ {
//don't allow deleting "Default" profile //don't allow deleting "Default" profile

View file

@ -14,12 +14,12 @@ class QMenu;
namespace Files { struct ConfigurationManager; } namespace Files { struct ConfigurationManager; }
namespace ContentSelectorView { class ContentSelector; } namespace ContentSelectorView { class ContentSelector; }
namespace Config { class GameSettings;
class LauncherSettings; }
namespace Launcher namespace Launcher
{ {
class TextInputDialog; class TextInputDialog;
class GameSettings;
class LauncherSettings;
class ProfilesComboBox; class ProfilesComboBox;
class DataFilesPage : public QWidget class DataFilesPage : public QWidget
@ -30,8 +30,8 @@ namespace Launcher
Ui::DataFilesPage ui; Ui::DataFilesPage ui;
public: public:
explicit DataFilesPage (Files::ConfigurationManager &cfg, GameSettings &gameSettings, explicit DataFilesPage (Files::ConfigurationManager &cfg, Config::GameSettings &gameSettings,
LauncherSettings &launcherSettings, QWidget *parent = 0); Config::LauncherSettings &launcherSettings, QWidget *parent = 0);
QAbstractItemModel* profilesModel() const; QAbstractItemModel* profilesModel() const;
@ -39,7 +39,7 @@ namespace Launcher
//void writeConfig(QString profile = QString()); //void writeConfig(QString profile = QString());
void saveSettings(const QString &profile = ""); void saveSettings(const QString &profile = "");
void loadSettings(); bool loadSettings();
signals: signals:
void signalProfileChanged (int index); void signalProfileChanged (int index);
@ -53,24 +53,27 @@ namespace Launcher
void slotProfileRenamed(const QString &previous, const QString &current); void slotProfileRenamed(const QString &previous, const QString &current);
void slotProfileDeleted(const QString &item); void slotProfileDeleted(const QString &item);
void updateOkButton(const QString &text);
void on_newProfileAction_triggered(); void on_newProfileAction_triggered();
void on_deleteProfileAction_triggered(); void on_deleteProfileAction_triggered();
private: private:
QMenu *mContextMenu; TextInputDialog *mProfileDialog;
Files::ConfigurationManager &mCfgMgr; Files::ConfigurationManager &mCfgMgr;
GameSettings &mGameSettings; Config::GameSettings &mGameSettings;
LauncherSettings &mLauncherSettings; Config::LauncherSettings &mLauncherSettings;
QString mPreviousProfile;
QString mDataLocal; QString mDataLocal;
void setPluginsCheckstates(Qt::CheckState state); void setPluginsCheckstates(Qt::CheckState state);
void buildView(); void buildView();
void setupDataFiles();
void setupConfig(); void setupConfig();
void readConfig(); void readConfig();
void setProfile (int index, bool savePrevious); void setProfile (int index, bool savePrevious);

View file

@ -137,6 +137,7 @@ bool Launcher::GraphicsPage::setupSDL()
return false; return false;
} }
screenComboBox->clear();
for (int i = 0; i < displays; i++) for (int i = 0; i < displays; i++)
{ {
screenComboBox->addItem(QString(tr("Screen ")) + QString::number(i + 1)); screenComboBox->addItem(QString(tr("Screen ")) + QString::number(i + 1));
@ -149,7 +150,7 @@ bool Launcher::GraphicsPage::loadSettings()
{ {
if (!setupSDL()) if (!setupSDL())
return false; return false;
if (!setupOgre()) if (!mOgre && !setupOgre())
return false; return false;
if (mGraphicsSettings.value(QString("Video/vsync")) == QLatin1String("true")) if (mGraphicsSettings.value(QString("Video/vsync")) == QLatin1String("true"))
@ -158,6 +159,9 @@ bool Launcher::GraphicsPage::loadSettings()
if (mGraphicsSettings.value(QString("Video/fullscreen")) == QLatin1String("true")) if (mGraphicsSettings.value(QString("Video/fullscreen")) == QLatin1String("true"))
fullScreenCheckBox->setCheckState(Qt::Checked); fullScreenCheckBox->setCheckState(Qt::Checked);
if (mGraphicsSettings.value(QString("Video/window border")) == QLatin1String("true"))
windowBorderCheckBox->setCheckState(Qt::Checked);
int aaIndex = antiAliasingComboBox->findText(mGraphicsSettings.value(QString("Video/antialiasing"))); int aaIndex = antiAliasingComboBox->findText(mGraphicsSettings.value(QString("Video/antialiasing")));
if (aaIndex != -1) if (aaIndex != -1)
antiAliasingComboBox->setCurrentIndex(aaIndex); antiAliasingComboBox->setCurrentIndex(aaIndex);
@ -192,6 +196,9 @@ void Launcher::GraphicsPage::saveSettings()
fullScreenCheckBox->checkState() ? mGraphicsSettings.setValue(QString("Video/fullscreen"), QString("true")) fullScreenCheckBox->checkState() ? mGraphicsSettings.setValue(QString("Video/fullscreen"), QString("true"))
: mGraphicsSettings.setValue(QString("Video/fullscreen"), QString("false")); : mGraphicsSettings.setValue(QString("Video/fullscreen"), QString("false"));
windowBorderCheckBox->checkState() ? mGraphicsSettings.setValue(QString("Video/window border"), QString("true"))
: mGraphicsSettings.setValue(QString("Video/window border"), QString("false"));
mGraphicsSettings.setValue(QString("Video/antialiasing"), antiAliasingComboBox->currentText()); mGraphicsSettings.setValue(QString("Video/antialiasing"), antiAliasingComboBox->currentText());
mGraphicsSettings.setValue(QString("Video/render system"), rendererComboBox->currentText()); mGraphicsSettings.setValue(QString("Video/render system"), rendererComboBox->currentText());
@ -330,10 +337,12 @@ void Launcher::GraphicsPage::slotFullScreenChanged(int state)
customRadioButton->setEnabled(false); customRadioButton->setEnabled(false);
customWidthSpinBox->setEnabled(false); customWidthSpinBox->setEnabled(false);
customHeightSpinBox->setEnabled(false); customHeightSpinBox->setEnabled(false);
windowBorderCheckBox->setEnabled(false);
} else { } else {
customRadioButton->setEnabled(true); customRadioButton->setEnabled(true);
customWidthSpinBox->setEnabled(true); customWidthSpinBox->setEnabled(true);
customHeightSpinBox->setEnabled(true); customHeightSpinBox->setEnabled(true);
windowBorderCheckBox->setEnabled(true);
} }
} }

View file

@ -52,11 +52,14 @@ int main(int argc, char *argv[])
Launcher::MainDialog mainWin; Launcher::MainDialog mainWin;
if (mainWin.setup()) { if (!mainWin.showFirstRunDialog())
mainWin.show();
} else {
return 0; return 0;
}
// if (!mainWin.setup()) {
// return 0;
// }
mainWin.show();
int returnValue = app.exec(); int returnValue = app.exec();
SDL_Quit(); SDL_Quit();

View file

@ -5,29 +5,24 @@
#include <QLabel> #include <QLabel>
#include <QDate> #include <QDate>
#include <QTime> #include <QTime>
#include <QMessageBox>
#include <QPushButton> #include <QPushButton>
#include <QFontDatabase> #include <QFontDatabase>
#include <QInputDialog> #include <QInputDialog>
#include <QFileDialog> #include <QFileDialog>
#include <QCloseEvent> #include <QCloseEvent>
#include <QTextCodec> #include <QTextCodec>
#include <QProcess>
#include <QFile> #include <QFile>
#include <QDir> #include <QDir>
#include <QDebug> #include <QDebug>
#ifndef WIN32
#include "unshieldthread.hpp"
#endif
#include "textslotmsgbox.hpp"
#include "utils/checkablemessagebox.hpp"
#include "playpage.hpp" #include "playpage.hpp"
#include "graphicspage.hpp" #include "graphicspage.hpp"
#include "datafilespage.hpp" #include "datafilespage.hpp"
#include "settingspage.hpp"
using namespace Process;
Launcher::MainDialog::MainDialog(QWidget *parent) Launcher::MainDialog::MainDialog(QWidget *parent)
: mGameSettings(mCfgMgr), QMainWindow (parent) : mGameSettings(mCfgMgr), QMainWindow (parent)
@ -53,6 +48,15 @@ Launcher::MainDialog::MainDialog(QWidget *parent)
setupUi(this); setupUi(this);
mGameInvoker = new ProcessInvoker();
mWizardInvoker = new ProcessInvoker();
connect(mWizardInvoker->getProcess(), SIGNAL(started()),
this, SLOT(wizardStarted()));
connect(mWizardInvoker->getProcess(), SIGNAL(finished(int,QProcess::ExitStatus)),
this, SLOT(wizardFinished(int,QProcess::ExitStatus)));
iconWidget->setViewMode(QListView::IconMode); iconWidget->setViewMode(QListView::IconMode);
iconWidget->setWrapping(false); iconWidget->setWrapping(false);
iconWidget->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); // Just to be sure iconWidget->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); // Just to be sure
@ -79,13 +83,13 @@ Launcher::MainDialog::MainDialog(QWidget *parent)
if (!revision.isEmpty() && !tag.isEmpty()) if (!revision.isEmpty() && !tag.isEmpty())
{ {
if (revision == tag) { if (revision == tag) {
versionLabel->setText(tr("OpenMW %0 release").arg(OPENMW_VERSION)); versionLabel->setText(tr("OpenMW %1 release").arg(OPENMW_VERSION));
} else { } else {
versionLabel->setText(tr("OpenMW development (%0)").arg(revision.left(10))); versionLabel->setText(tr("OpenMW development (%1)").arg(revision.left(10)));
} }
// Add the compile date and time // Add the compile date and time
versionLabel->setToolTip(tr("Compiled on %0 %1").arg(QLocale(QLocale::C).toDate(QString(__DATE__).simplified(), versionLabel->setToolTip(tr("Compiled on %1 %2").arg(QLocale(QLocale::C).toDate(QString(__DATE__).simplified(),
QLatin1String("MMM d yyyy")).toString(Qt::SystemLocaleLongDate), QLatin1String("MMM d yyyy")).toString(Qt::SystemLocaleLongDate),
QLocale(QLocale::C).toTime(QString(__TIME__).simplified(), QLocale(QLocale::C).toTime(QString(__TIME__).simplified(),
QLatin1String("hh:mm:ss")).toString(Qt::SystemLocaleShortDate))); QLatin1String("hh:mm:ss")).toString(Qt::SystemLocaleShortDate)));
@ -94,32 +98,41 @@ Launcher::MainDialog::MainDialog(QWidget *parent)
createIcons(); createIcons();
} }
Launcher::MainDialog::~MainDialog()
{
delete mGameInvoker;
delete mWizardInvoker;
}
void Launcher::MainDialog::createIcons() void Launcher::MainDialog::createIcons()
{ {
if (!QIcon::hasThemeIcon("document-new")) if (!QIcon::hasThemeIcon("document-new"))
QIcon::setThemeName("tango"); QIcon::setThemeName("tango");
// We create a fallback icon because the default fallback doesn't work
QIcon graphicsIcon = QIcon(":/icons/tango/video-display.png");
QListWidgetItem *playButton = new QListWidgetItem(iconWidget); QListWidgetItem *playButton = new QListWidgetItem(iconWidget);
playButton->setIcon(QIcon(":/images/openmw.png")); playButton->setIcon(QIcon(":/images/openmw.png"));
playButton->setText(tr("Play")); playButton->setText(tr("Play"));
playButton->setTextAlignment(Qt::AlignCenter); playButton->setTextAlignment(Qt::AlignCenter);
playButton->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled); playButton->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled);
QListWidgetItem *graphicsButton = new QListWidgetItem(iconWidget);
graphicsButton->setIcon(QIcon::fromTheme("video-display", graphicsIcon));
graphicsButton->setText(tr("Graphics"));
graphicsButton->setTextAlignment(Qt::AlignHCenter | Qt::AlignBottom | Qt::AlignAbsolute);
graphicsButton->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled);
QListWidgetItem *dataFilesButton = new QListWidgetItem(iconWidget); QListWidgetItem *dataFilesButton = new QListWidgetItem(iconWidget);
dataFilesButton->setIcon(QIcon(":/images/openmw-plugin.png")); dataFilesButton->setIcon(QIcon(":/images/openmw-plugin.png"));
dataFilesButton->setText(tr("Data Files")); dataFilesButton->setText(tr("Data Files"));
dataFilesButton->setTextAlignment(Qt::AlignHCenter | Qt::AlignBottom); dataFilesButton->setTextAlignment(Qt::AlignHCenter | Qt::AlignBottom);
dataFilesButton->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled); dataFilesButton->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled);
QListWidgetItem *graphicsButton = new QListWidgetItem(iconWidget);
graphicsButton->setIcon(QIcon::fromTheme("video-display"));
graphicsButton->setText(tr("Graphics"));
graphicsButton->setTextAlignment(Qt::AlignHCenter | Qt::AlignBottom | Qt::AlignAbsolute);
graphicsButton->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled);
QListWidgetItem *settingsButton = new QListWidgetItem(iconWidget);
settingsButton->setIcon(QIcon::fromTheme("preferences-system"));
settingsButton->setText(tr("Settings"));
settingsButton->setTextAlignment(Qt::AlignHCenter | Qt::AlignBottom);
settingsButton->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled);
connect(iconWidget, connect(iconWidget,
SIGNAL(currentItemChanged(QListWidgetItem*,QListWidgetItem*)), SIGNAL(currentItemChanged(QListWidgetItem*,QListWidgetItem*)),
this, SLOT(changePage(QListWidgetItem*,QListWidgetItem*))); this, SLOT(changePage(QListWidgetItem*,QListWidgetItem*)));
@ -129,8 +142,9 @@ void Launcher::MainDialog::createIcons()
void Launcher::MainDialog::createPages() void Launcher::MainDialog::createPages()
{ {
mPlayPage = new PlayPage(this); mPlayPage = new PlayPage(this);
mGraphicsPage = new GraphicsPage(mCfgMgr, mGraphicsSettings, this);
mDataFilesPage = new DataFilesPage(mCfgMgr, mGameSettings, mLauncherSettings, this); mDataFilesPage = new DataFilesPage(mCfgMgr, mGameSettings, mLauncherSettings, this);
mGraphicsPage = new GraphicsPage(mCfgMgr, mGraphicsSettings, this);
mSettingsPage = new SettingsPage(mCfgMgr, mGameSettings, mLauncherSettings, this);
// Set the combobox of the play page to imitate the combobox on the datafilespage // Set the combobox of the play page to imitate the combobox on the datafilespage
mPlayPage->setProfilesModel(mDataFilesPage->profilesModel()); mPlayPage->setProfilesModel(mDataFilesPage->profilesModel());
@ -138,8 +152,9 @@ void Launcher::MainDialog::createPages()
// Add the pages to the stacked widget // Add the pages to the stacked widget
pagesWidget->addWidget(mPlayPage); pagesWidget->addWidget(mPlayPage);
pagesWidget->addWidget(mGraphicsPage);
pagesWidget->addWidget(mDataFilesPage); pagesWidget->addWidget(mDataFilesPage);
pagesWidget->addWidget(mGraphicsPage);
pagesWidget->addWidget(mSettingsPage);
// Select the first page // Select the first page
iconWidget->setCurrentItem(iconWidget->item(0), QItemSelectionModel::Select); iconWidget->setCurrentItem(iconWidget->item(0), QItemSelectionModel::Select);
@ -153,153 +168,63 @@ void Launcher::MainDialog::createPages()
bool Launcher::MainDialog::showFirstRunDialog() bool Launcher::MainDialog::showFirstRunDialog()
{ {
QStringList iniPaths; if (!setupLauncherSettings())
return false;
foreach (const QString &path, mGameSettings.getDataDirs()) { if (mLauncherSettings.value(QString("General/firstrun"), QString("true")) == QLatin1String("true"))
QDir dir(path);
dir.setPath(dir.canonicalPath()); // Resolve symlinks
if (dir.exists(QString("Morrowind.ini")))
iniPaths.append(dir.absoluteFilePath(QString("Morrowind.ini")));
else
{ {
if (!dir.cdUp())
continue; // Cannot move from Data Files
if (dir.exists(QString("Morrowind.ini")))
iniPaths.append(dir.absoluteFilePath(QString("Morrowind.ini")));
}
}
// Ask the user where the Morrowind.ini is
if (iniPaths.empty()) {
QMessageBox msgBox; QMessageBox msgBox;
msgBox.setWindowTitle(tr("Error detecting Morrowind configuration")); msgBox.setWindowTitle(tr("First run"));
msgBox.setIcon(QMessageBox::Warning); msgBox.setIcon(QMessageBox::Question);
msgBox.setStandardButtons(QMessageBox::Cancel); msgBox.setStandardButtons(QMessageBox::NoButton);
msgBox.setText(QObject::tr("<br><b>Could not find Morrowind.ini</b><br><br> \ msgBox.setText(tr("<html><head/><body><p><b>Welcome to OpenMW!</b></p> \
OpenMW needs to import settings from this file.<br><br> \ <p>It is recommended to run the Installation Wizard.</p> \
Press \"Browse...\" to specify the location manually.<br>")); <p>The Wizard will let you select an existing Morrowind installation, \
or install Morrowind for OpenMW to use.</p></body></html>"));
QAbstractButton *dirSelectButton = QAbstractButton *wizardButton =
msgBox.addButton(QObject::tr("B&rowse..."), QMessageBox::ActionRole); msgBox.addButton(tr("Run &Installation Wizard"), QMessageBox::AcceptRole); // ActionRole doesn't work?!
msgBox.exec();
QString iniFile;
if (msgBox.clickedButton() == dirSelectButton) {
iniFile = QFileDialog::getOpenFileName(
NULL,
QObject::tr("Select configuration file"),
QDir::currentPath(),
QString(tr("Morrowind configuration file (*.ini)")));
}
if (iniFile.isEmpty())
return false; // Cancel was clicked;
QFileInfo info(iniFile);
iniPaths.clear();
iniPaths.append(info.absoluteFilePath());
}
CheckableMessageBox msgBox(this);
msgBox.setWindowTitle(tr("Morrowind installation detected"));
QIcon icon = QApplication::style()->standardIcon(QStyle::SP_MessageBoxQuestion);
int size = QApplication::style()->pixelMetric(QStyle::PM_MessageBoxIconSize);
msgBox.setIconPixmap(icon.pixmap(size, size));
QAbstractButton *importerButton =
msgBox.addButton(tr("Import"), QDialogButtonBox::AcceptRole); // ActionRole doesn't work?!
QAbstractButton *skipButton = QAbstractButton *skipButton =
msgBox.addButton(tr("Skip"), QDialogButtonBox::RejectRole); msgBox.addButton(tr("Skip"), QMessageBox::RejectRole);
Q_UNUSED(skipButton); // Surpress compiler unused warning Q_UNUSED(skipButton); // Surpress compiler unused warning
msgBox.setStandardButtons(QDialogButtonBox::NoButton);
msgBox.setText(tr("<br><b>An existing Morrowind configuration was detected</b><br> \
<br>Would you like to import settings from Morrowind.ini?<br> \
<br><b>Warning: In most cases OpenMW needs these settings to run properly</b><br>"));
msgBox.setCheckBoxText(tr("Include selected masters and plugins (creates a new profile)"));
msgBox.exec(); msgBox.exec();
if (msgBox.clickedButton() == wizardButton)
if (msgBox.clickedButton() == importerButton) { {
if (!mWizardInvoker->startProcess(QLatin1String("openmw-wizard"), false)) {
if (iniPaths.count() > 1) { return false;
// Multiple Morrowind.ini files found
bool ok;
QString path = QInputDialog::getItem(this, tr("Multiple configurations found"),
tr("<br><b>There are multiple Morrowind.ini files found.</b><br><br> \
Please select the one you wish to import from:"), iniPaths, 0, false, &ok);
if (ok && !path.isEmpty()) {
iniPaths.clear();
iniPaths.append(path);
} else { } else {
// Cancel was clicked return true;
return false; }
} }
} }
// Create the file if it doesn't already exist, else the importer will fail return setup();
QString path = QString::fromUtf8(mCfgMgr.getUserConfigPath().string().c_str()) + QString("openmw.cfg"); }
QFile file(path);
if (!file.exists()) { bool Launcher::MainDialog::setup()
if (!file.open(QIODevice::ReadWrite)) { {
// File cannot be created
QMessageBox msgBox;
msgBox.setWindowTitle(tr("Error writing OpenMW configuration file"));
msgBox.setIcon(QMessageBox::Critical);
msgBox.setStandardButtons(QMessageBox::Ok);
msgBox.setText(tr("<br><b>Could not open or create %0 for writing</b><br><br> \
Please make sure you have the right permissions \
and try again.<br>").arg(file.fileName()));
msgBox.exec();
return false;
}
file.close();
}
// Construct the arguments to run the importer
QStringList arguments;
if (msgBox.isChecked())
arguments.append(QString("--game-files"));
arguments.append(QString("--encoding"));
arguments.append(mGameSettings.value(QString("encoding"), QString("win1252")));
arguments.append(QString("--ini"));
arguments.append(iniPaths.first());
arguments.append(QString("--cfg"));
arguments.append(path);
if (!startProgram(QString("mwiniimport"), arguments, false))
return false;
// Re-read the game settings
if (!setupGameSettings()) if (!setupGameSettings())
return false; return false;
// Add a new profile if (!setupGraphicsSettings())
if (msgBox.isChecked()) { return false;
mLauncherSettings.setValue(QString("Profiles/currentprofile"), QString("Imported"));
mLauncherSettings.remove(QString("Profiles/Imported/content"));
QStringList contents = mGameSettings.values(QString("content")); // Now create the pages as they need the settings
foreach (const QString &content, contents) { createPages();
mLauncherSettings.setMultiValue(QString("Profiles/Imported/content"), content);
}
}
} // Call this so we can exit on Ogre/SDL errors before mainwindow is shown
if (!mGraphicsPage->loadSettings())
return false;
loadSettings();
return true; return true;
} }
bool Launcher::MainDialog::setup() bool Launcher::MainDialog::reloadSettings()
{ {
if (!setupLauncherSettings()) if (!setupLauncherSettings())
return false; return false;
@ -310,21 +235,15 @@ bool Launcher::MainDialog::setup()
if (!setupGraphicsSettings()) if (!setupGraphicsSettings())
return false; return false;
// Check if we need to show the importer if (!mSettingsPage->loadSettings())
if (mLauncherSettings.value(QString("General/firstrun"), QString("true")) == QLatin1String("true"))
{
if (!showFirstRunDialog())
return false; return false;
}
// Now create the pages as they need the settings if (!mDataFilesPage->loadSettings())
createPages(); return false;
// Call this so we can exit on Ogre/SDL errors before mainwindow is shown
if (!mGraphicsPage->loadSettings()) if (!mGraphicsPage->loadSettings())
return false; return false;
loadSettings();
return true; return true;
} }
@ -334,24 +253,24 @@ void Launcher::MainDialog::changePage(QListWidgetItem *current, QListWidgetItem
current = previous; current = previous;
int currentIndex = iconWidget->row(current); int currentIndex = iconWidget->row(current);
int previousIndex = iconWidget->row(previous); // int previousIndex = iconWidget->row(previous);
pagesWidget->setCurrentIndex(currentIndex); pagesWidget->setCurrentIndex(currentIndex);
DataFilesPage *previousPage = dynamic_cast<DataFilesPage *>(pagesWidget->widget(previousIndex)); // DataFilesPage *previousPage = dynamic_cast<DataFilesPage *>(pagesWidget->widget(previousIndex));
DataFilesPage *currentPage = dynamic_cast<DataFilesPage *>(pagesWidget->widget(currentIndex)); // DataFilesPage *currentPage = dynamic_cast<DataFilesPage *>(pagesWidget->widget(currentIndex));
//special call to update/save data files page list view when it's displayed/hidden. // //special call to update/save data files page list view when it's displayed/hidden.
if (previousPage) // if (previousPage)
{ // {
if (previousPage->objectName() == "DataFilesPage") // if (previousPage->objectName() == "DataFilesPage")
previousPage->saveSettings(); // previousPage->saveSettings();
} // }
else if (currentPage) // else if (currentPage)
{ // {
if (currentPage->objectName() == "DataFilesPage") // if (currentPage->objectName() == "DataFilesPage")
currentPage->loadSettings(); // currentPage->loadSettings();
} // }
} }
bool Launcher::MainDialog::setupLauncherSettings() bool Launcher::MainDialog::setupLauncherSettings()
@ -373,7 +292,7 @@ bool Launcher::MainDialog::setupLauncherSettings()
msgBox.setWindowTitle(tr("Error opening OpenMW configuration file")); msgBox.setWindowTitle(tr("Error opening OpenMW configuration file"));
msgBox.setIcon(QMessageBox::Critical); msgBox.setIcon(QMessageBox::Critical);
msgBox.setStandardButtons(QMessageBox::Ok); msgBox.setStandardButtons(QMessageBox::Ok);
msgBox.setText(QObject::tr("<br><b>Could not open %0 for reading</b><br><br> \ msgBox.setText(tr("<br><b>Could not open %0 for reading</b><br><br> \
Please make sure you have the right permissions \ Please make sure you have the right permissions \
and try again.<br>").arg(file.fileName())); and try again.<br>").arg(file.fileName()));
msgBox.exec(); msgBox.exec();
@ -390,78 +309,6 @@ bool Launcher::MainDialog::setupLauncherSettings()
return true; return true;
} }
#ifndef WIN32
bool Launcher::expansions(Launcher::UnshieldThread& cd)
{
if(cd.BloodmoonDone())
{
cd.Done();
return false;
}
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);
QAbstractButton* bloodmoonButton = expansionsBox.addButton(QObject::tr("&Bloodmoon"), QMessageBox::ActionRole);
QAbstractButton* noneButton = expansionsBox.addButton(QObject::tr("&None"), QMessageBox::ActionRole);
expansionsBox.exec();
if(expansionsBox.clickedButton() == noneButton)
{
cd.Done();
return false;
}
else if(expansionsBox.clickedButton() == tribunalButton)
{
TextSlotMsgBox cdbox;
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.SetTribunalPath(
QFileDialog::getOpenFileName(
NULL,
QObject::tr("Select data1.hdr from Tribunal Installation CD (Tribunal/data1.hdr on GOTY CDs)"),
QDir::currentPath(),
QString(QObject::tr("Installshield hdr file (*.hdr)"))).toUtf8().constData());
cd.start();
cdbox.exec();
}
else if(expansionsBox.clickedButton() == bloodmoonButton)
{
TextSlotMsgBox cdbox;
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.SetBloodmoonPath(
QFileDialog::getOpenFileName(
NULL,
QObject::tr("Select data1.hdr from Bloodmoon Installation CD (Bloodmoon/data1.hdr on GOTY CDs)"),
QDir::currentPath(),
QString(QObject::tr("Installshield hdr file (*.hdr)"))).toUtf8().constData());
cd.start();
cdbox.exec();
}
return true;
}
#endif // WIN32
bool Launcher::MainDialog::setupGameSettings() bool Launcher::MainDialog::setupGameSettings()
{ {
QString userPath = QString::fromUtf8(mCfgMgr.getUserConfigPath().string().c_str()); QString userPath = QString::fromUtf8(mCfgMgr.getUserConfigPath().string().c_str());
@ -480,7 +327,7 @@ bool Launcher::MainDialog::setupGameSettings()
msgBox.setWindowTitle(tr("Error opening OpenMW configuration file")); msgBox.setWindowTitle(tr("Error opening OpenMW configuration file"));
msgBox.setIcon(QMessageBox::Critical); msgBox.setIcon(QMessageBox::Critical);
msgBox.setStandardButtons(QMessageBox::Ok); msgBox.setStandardButtons(QMessageBox::Ok);
msgBox.setText(QObject::tr("<br><b>Could not open %0 for reading</b><br><br> \ msgBox.setText(tr("<br><b>Could not open %0 for reading</b><br><br> \
Please make sure you have the right permissions \ Please make sure you have the right permissions \
and try again.<br>").arg(file.fileName())); and try again.<br>").arg(file.fileName()));
msgBox.exec(); msgBox.exec();
@ -508,7 +355,7 @@ bool Launcher::MainDialog::setupGameSettings()
msgBox.setWindowTitle(tr("Error opening OpenMW configuration file")); msgBox.setWindowTitle(tr("Error opening OpenMW configuration file"));
msgBox.setIcon(QMessageBox::Critical); msgBox.setIcon(QMessageBox::Critical);
msgBox.setStandardButtons(QMessageBox::Ok); msgBox.setStandardButtons(QMessageBox::Ok);
msgBox.setText(QObject::tr("<br><b>Could not open %0 for reading</b><br><br> \ msgBox.setText(tr("<br><b>Could not open %0 for reading</b><br><br> \
Please make sure you have the right permissions \ Please make sure you have the right permissions \
and try again.<br>").arg(file.fileName())); and try again.<br>").arg(file.fileName()));
msgBox.exec(); msgBox.exec();
@ -540,72 +387,22 @@ bool Launcher::MainDialog::setupGameSettings()
msgBox.setWindowTitle(tr("Error detecting Morrowind installation")); msgBox.setWindowTitle(tr("Error detecting Morrowind installation"));
msgBox.setIcon(QMessageBox::Warning); msgBox.setIcon(QMessageBox::Warning);
msgBox.setStandardButtons(QMessageBox::Cancel); msgBox.setStandardButtons(QMessageBox::Cancel);
msgBox.setText(QObject::tr("<br><b>Could not find the Data Files location</b><br><br> \ msgBox.setText(tr("<br><b>Could not find the Data Files location</b><br><br> \
The directory containing the data files was not found.<br><br> \ The directory containing the data files was not found."));
Press \"Browse...\" to specify the location manually.<br>"));
QAbstractButton *dirSelectButton =
msgBox.addButton(QObject::tr("Browse to &Install..."), QMessageBox::ActionRole);
#ifndef WIN32
QAbstractButton *cdSelectButton =
msgBox.addButton(QObject::tr("Browse to &CD..."), QMessageBox::ActionRole);
#endif
QAbstractButton *wizardButton =
msgBox.addButton(tr("Run &Installation Wizard..."), QMessageBox::ActionRole);
msgBox.exec(); msgBox.exec();
QString selectedFile; if (msgBox.clickedButton() == wizardButton)
if (msgBox.clickedButton() == dirSelectButton) {
selectedFile = QFileDialog::getOpenFileName(
NULL,
QObject::tr("Select master file"),
QDir::currentPath(),
QString(tr("Morrowind master file (*.esm)")));
}
#ifndef WIN32
else if(msgBox.clickedButton() == cdSelectButton) {
UnshieldThread cd;
{ {
TextSlotMsgBox cdbox; if (!mWizardInvoker->startProcess(QLatin1String("openmw-wizard"), false)) {
cdbox.setStandardButtons(QMessageBox::Cancel); return false;
} else {
QObject::connect(&cd,SIGNAL(signalGUI(const QString&)), &cdbox, SLOT(setTextSlot(const QString&))); return true;
QObject::connect(&cd,SIGNAL(close()), &cdbox, SLOT(reject()));
cd.SetMorrowindPath(
QFileDialog::getOpenFileName(
NULL,
QObject::tr("Select data1.hdr from Morrowind Installation CD"),
QDir::currentPath(),
QString(tr("Installshield hdr file (*.hdr)"))).toUtf8().constData());
cd.SetOutputPath(
QFileDialog::getExistingDirectory(
NULL,
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::fromUtf8(cd.GetMWEsmPath().c_str());
} }
#endif // WIN32
if (selectedFile.isEmpty())
return false; // Cancel was clicked;
QFileInfo info(selectedFile);
// Add the new dir to the settings file and to the data dir container
mGameSettings.setMultiValue(QString("data"), info.absolutePath());
mGameSettings.addDataDir(info.absolutePath());
} }
return true; return true;
@ -626,7 +423,7 @@ bool Launcher::MainDialog::setupGraphicsSettings()
msgBox.setWindowTitle(tr("Error reading OpenMW configuration file")); msgBox.setWindowTitle(tr("Error reading OpenMW configuration file"));
msgBox.setIcon(QMessageBox::Critical); msgBox.setIcon(QMessageBox::Critical);
msgBox.setStandardButtons(QMessageBox::Ok); msgBox.setStandardButtons(QMessageBox::Ok);
msgBox.setText(QObject::tr("<br><b>Could not find settings-default.cfg</b><br><br> \ msgBox.setText(tr("<br><b>Could not find settings-default.cfg</b><br><br> \
The problem may be due to an incomplete installation of OpenMW.<br> \ The problem may be due to an incomplete installation of OpenMW.<br> \
Reinstalling OpenMW may resolve the problem.")); Reinstalling OpenMW may resolve the problem."));
msgBox.exec(); msgBox.exec();
@ -648,7 +445,7 @@ bool Launcher::MainDialog::setupGraphicsSettings()
msgBox.setWindowTitle(tr("Error opening OpenMW configuration file")); msgBox.setWindowTitle(tr("Error opening OpenMW configuration file"));
msgBox.setIcon(QMessageBox::Critical); msgBox.setIcon(QMessageBox::Critical);
msgBox.setStandardButtons(QMessageBox::Ok); msgBox.setStandardButtons(QMessageBox::Ok);
msgBox.setText(QObject::tr("<br><b>Could not open %0 for reading</b><br><br> \ msgBox.setText(tr("<br><b>Could not open %0 for reading</b><br><br> \
Please make sure you have the right permissions \ Please make sure you have the right permissions \
and try again.<br>").arg(file.fileName())); and try again.<br>").arg(file.fileName()));
msgBox.exec(); msgBox.exec();
@ -699,8 +496,9 @@ bool Launcher::MainDialog::writeSettings()
{ {
// Now write all config files // Now write all config files
saveSettings(); saveSettings();
mGraphicsPage->saveSettings();
mDataFilesPage->saveSettings(); mDataFilesPage->saveSettings();
mGraphicsPage->saveSettings();
mSettingsPage->saveSettings();
QString userPath = QString::fromUtf8(mCfgMgr.getUserConfigPath().string().c_str()); QString userPath = QString::fromUtf8(mCfgMgr.getUserConfigPath().string().c_str());
QDir dir(userPath); QDir dir(userPath);
@ -794,14 +592,29 @@ void Launcher::MainDialog::closeEvent(QCloseEvent *event)
event->accept(); event->accept();
} }
void Launcher::MainDialog::wizardStarted()
{
hide();
}
void Launcher::MainDialog::wizardFinished(int exitCode, QProcess::ExitStatus exitStatus)
{
if (exitCode != 0 || exitStatus == QProcess::CrashExit)
return qApp->quit();
// HACK: Ensure the pages are created, else segfault
setup();
if (reloadSettings())
show();
}
void Launcher::MainDialog::play() void Launcher::MainDialog::play()
{ {
if (!writeSettings()) { if (!writeSettings())
qApp->quit(); return qApp->quit();
return;
}
if(!mGameSettings.hasMaster()) { if (!mGameSettings.hasMaster()) {
QMessageBox msgBox; QMessageBox msgBox;
msgBox.setWindowTitle(tr("No game file selected")); msgBox.setWindowTitle(tr("No game file selected"));
msgBox.setIcon(QMessageBox::Warning); msgBox.setIcon(QMessageBox::Warning);
@ -813,103 +626,7 @@ void Launcher::MainDialog::play()
} }
// Launch the game detached // Launch the game detached
startProgram(QString("openmw"), true);
qApp->quit(); if (mGameInvoker->startProcess(QLatin1String("openmw"), true))
} return qApp->quit();
bool Launcher::MainDialog::startProgram(const QString &name, const QStringList &arguments, bool detached)
{
QString path = name;
#ifdef Q_OS_WIN
path.append(QString(".exe"));
#elif defined(Q_OS_MAC)
QDir dir(QCoreApplication::applicationDirPath());
path = dir.absoluteFilePath(name);
#else
path.prepend(QString("./"));
#endif
QFile file(path);
QProcess process;
QFileInfo info(file);
if (!file.exists()) {
QMessageBox msgBox;
msgBox.setWindowTitle(tr("Error starting executable"));
msgBox.setIcon(QMessageBox::Warning);
msgBox.setStandardButtons(QMessageBox::Ok);
msgBox.setText(tr("<br><b>Could not find %1</b><br><br> \
The application is not found.<br> \
Please make sure OpenMW is installed correctly and try again.<br>").arg(info.fileName()));
msgBox.exec();
return false;
}
if (!info.isExecutable()) {
QMessageBox msgBox;
msgBox.setWindowTitle(tr("Error starting executable"));
msgBox.setIcon(QMessageBox::Warning);
msgBox.setStandardButtons(QMessageBox::Ok);
msgBox.setText(tr("<br><b>Could not start %1</b><br><br> \
The application is not executable.<br> \
Please make sure you have the right permissions and try again.<br>").arg(info.fileName()));
msgBox.exec();
return false;
}
// Start the executable
if (detached) {
if (!process.startDetached(path, arguments)) {
QMessageBox msgBox;
msgBox.setWindowTitle(tr("Error starting executable"));
msgBox.setIcon(QMessageBox::Critical);
msgBox.setStandardButtons(QMessageBox::Ok);
msgBox.setText(tr("<br><b>Could not start %1</b><br><br> \
An error occurred while starting %1.<br><br> \
Press \"Show Details...\" for more information.<br>").arg(info.fileName()));
msgBox.setDetailedText(process.errorString());
msgBox.exec();
return false;
}
} else {
process.start(path, arguments);
if (!process.waitForFinished()) {
QMessageBox msgBox;
msgBox.setWindowTitle(tr("Error starting executable"));
msgBox.setIcon(QMessageBox::Critical);
msgBox.setStandardButtons(QMessageBox::Ok);
msgBox.setText(tr("<br><b>Could not start %1</b><br><br> \
An error occurred while starting %1.<br><br> \
Press \"Show Details...\" for more information.<br>").arg(info.fileName()));
msgBox.setDetailedText(process.errorString());
msgBox.exec();
return false;
}
if (process.exitCode() != 0 || process.exitStatus() == QProcess::CrashExit) {
QString error(process.readAllStandardError());
error.append(tr("\nArguments:\n"));
error.append(arguments.join(" "));
QMessageBox msgBox;
msgBox.setWindowTitle(tr("Error running executable"));
msgBox.setIcon(QMessageBox::Critical);
msgBox.setStandardButtons(QMessageBox::Ok);
msgBox.setText(tr("<br><b>Executable %1 returned an error</b><br><br> \
An error occurred while running %1.<br><br> \
Press \"Show Details...\" for more information.<br>").arg(info.fileName()));
msgBox.setDetailedText(error);
msgBox.exec();
return false;
}
}
return true;
} }

View file

@ -2,16 +2,26 @@
#define MAINDIALOG_H #define MAINDIALOG_H
#include <QMainWindow> #include <QMainWindow>
#include <QProcess>
#ifndef Q_MOC_RUN #ifndef Q_MOC_RUN
#include <components/files/configurationmanager.hpp> #include <components/files/configurationmanager.hpp>
#endif #endif
#include "settings/gamesettings.hpp"
#include <components/process/processinvoker.hpp>
#include <components/config/gamesettings.hpp>
#include <components/config/launchersettings.hpp>
#include "settings/graphicssettings.hpp" #include "settings/graphicssettings.hpp"
#include "settings/launchersettings.hpp"
#include "ui_mainwindow.h" #include "ui_mainwindow.h"
class QListWidgetItem; class QListWidgetItem;
class QStackedWidget;
class QStringList;
class QStringListModel;
class QString;
namespace Launcher namespace Launcher
{ {
@ -19,6 +29,7 @@ namespace Launcher
class GraphicsPage; class GraphicsPage;
class DataFilesPage; class DataFilesPage;
class UnshieldThread; class UnshieldThread;
class SettingsPage;
#ifndef WIN32 #ifndef WIN32
bool expansions(Launcher::UnshieldThread& cd); bool expansions(Launcher::UnshieldThread& cd);
@ -30,13 +41,22 @@ namespace Launcher
public: public:
explicit MainDialog(QWidget *parent = 0); explicit MainDialog(QWidget *parent = 0);
~MainDialog();
bool setup(); bool setup();
bool showFirstRunDialog(); bool showFirstRunDialog();
bool reloadSettings();
bool writeSettings();
public slots: public slots:
void changePage(QListWidgetItem *current, QListWidgetItem *previous); void changePage(QListWidgetItem *current, QListWidgetItem *previous);
void play(); void play();
private slots:
void wizardStarted();
void wizardFinished(int exitCode, QProcess::ExitStatus exitStatus);
private: private:
void createIcons(); void createIcons();
void createPages(); void createPages();
@ -47,7 +67,6 @@ namespace Launcher
void loadSettings(); void loadSettings();
void saveSettings(); void saveSettings();
bool writeSettings();
inline bool startProgram(const QString &name, bool detached = false) { return startProgram(name, QStringList(), detached); } 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); bool startProgram(const QString &name, const QStringList &arguments, bool detached = false);
@ -57,12 +76,16 @@ namespace Launcher
PlayPage *mPlayPage; PlayPage *mPlayPage;
GraphicsPage *mGraphicsPage; GraphicsPage *mGraphicsPage;
DataFilesPage *mDataFilesPage; DataFilesPage *mDataFilesPage;
SettingsPage *mSettingsPage;
Process::ProcessInvoker *mGameInvoker;
Process::ProcessInvoker *mWizardInvoker;
Files::ConfigurationManager mCfgMgr; Files::ConfigurationManager mCfgMgr;
GameSettings mGameSettings; Config::GameSettings mGameSettings;
GraphicsSettings mGraphicsSettings; GraphicsSettings mGraphicsSettings;
LauncherSettings mLauncherSettings; Config::LauncherSettings mLauncherSettings;
}; };
} }

View file

@ -1,11 +1,11 @@
#ifndef GRAPHICSSETTINGS_HPP #ifndef GRAPHICSSETTINGS_HPP
#define GRAPHICSSETTINGS_HPP #define GRAPHICSSETTINGS_HPP
#include "settingsbase.hpp" #include <components/config/settingsbase.hpp>
namespace Launcher namespace Launcher
{ {
class GraphicsSettings : public SettingsBase<QMap<QString, QString> > class GraphicsSettings : public Config::SettingsBase<QMap<QString, QString> >
{ {
public: public:
GraphicsSettings(); GraphicsSettings();

View file

@ -0,0 +1,269 @@
#include "settingspage.hpp"
#include <QFileDialog>
#include <QMessageBox>
#include <QDebug>
#include <QDir>
#include <components/files/configurationmanager.hpp>
#include <components/config/gamesettings.hpp>
#include <components/config/launchersettings.hpp>
#include "utils/textinputdialog.hpp"
using namespace Process;
Launcher::SettingsPage::SettingsPage(Files::ConfigurationManager &cfg,
Config::GameSettings &gameSettings,
Config::LauncherSettings &launcherSettings, MainDialog *parent)
: mCfgMgr(cfg)
, mGameSettings(gameSettings)
, mLauncherSettings(launcherSettings)
, QWidget(parent)
, mMain(parent)
{
setupUi(this);
QStringList languages;
languages << QLatin1String("English")
<< QLatin1String("French")
<< QLatin1String("German")
<< QLatin1String("Italian")
<< QLatin1String("Polish")
<< QLatin1String("Russian")
<< QLatin1String("Spanish");
languageComboBox->addItems(languages);
mWizardInvoker = new ProcessInvoker();
mImporterInvoker = new ProcessInvoker();
connect(mWizardInvoker->getProcess(), SIGNAL(started()),
this, SLOT(wizardStarted()));
connect(mWizardInvoker->getProcess(), SIGNAL(finished(int,QProcess::ExitStatus)),
this, SLOT(wizardFinished(int,QProcess::ExitStatus)));
connect(mImporterInvoker->getProcess(), SIGNAL(started()),
this, SLOT(importerStarted()));
connect(mImporterInvoker->getProcess(), SIGNAL(finished(int,QProcess::ExitStatus)),
this, SLOT(importerFinished(int,QProcess::ExitStatus)));
mProfileDialog = new TextInputDialog(tr("New Profile"), tr("Profile name:"), this);
connect(mProfileDialog->lineEdit(), SIGNAL(textChanged(QString)),
this, SLOT(updateOkButton(QString)));
// Detect Morrowind configuration files
QStringList iniPaths;
foreach (const QString &path, mGameSettings.getDataDirs()) {
QDir dir(path);
dir.setPath(dir.canonicalPath()); // Resolve symlinks
if (dir.exists(QString("Morrowind.ini")))
iniPaths.append(dir.absoluteFilePath(QString("Morrowind.ini")));
else
{
if (!dir.cdUp())
continue; // Cannot move from Data Files
if (dir.exists(QString("Morrowind.ini")))
iniPaths.append(dir.absoluteFilePath(QString("Morrowind.ini")));
}
}
if (!iniPaths.isEmpty()) {
settingsComboBox->addItems(iniPaths);
importerButton->setEnabled(true);
} else {
importerButton->setEnabled(false);
}
loadSettings();
}
Launcher::SettingsPage::~SettingsPage()
{
delete mWizardInvoker;
delete mImporterInvoker;
}
void Launcher::SettingsPage::on_wizardButton_clicked()
{
saveSettings();
if (!mWizardInvoker->startProcess(QLatin1String("openmw-wizard"), false))
return;
}
void Launcher::SettingsPage::on_importerButton_clicked()
{
saveSettings();
// Create the file if it doesn't already exist, else the importer will fail
QString path(QString::fromUtf8(mCfgMgr.getUserConfigPath().string().c_str()));
path.append(QLatin1String("openmw.cfg"));
QFile file(path);
if (!file.exists()) {
if (!file.open(QIODevice::ReadWrite)) {
// File cannot be created
QMessageBox msgBox;
msgBox.setWindowTitle(tr("Error writing OpenMW configuration file"));
msgBox.setIcon(QMessageBox::Critical);
msgBox.setStandardButtons(QMessageBox::Ok);
msgBox.setText(tr("<html><head/><body><p><b>Could not open or create %1 for writing </b></p> \
<p>Please make sure you have the right permissions \
and try again.</p></body></html>").arg(file.fileName()));
msgBox.exec();
return;
}
file.close();
}
// Construct the arguments to run the importer
QStringList arguments;
if (addonsCheckBox->isChecked())
arguments.append(QString("--game-files"));
arguments.append(QString("--encoding"));
arguments.append(mGameSettings.value(QString("encoding"), QString("win1252")));
arguments.append(QString("--ini"));
arguments.append(settingsComboBox->currentText());
arguments.append(QString("--cfg"));
arguments.append(path);
qDebug() << "arguments " << arguments;
if (!mImporterInvoker->startProcess(QLatin1String("mwiniimport"), arguments, false))
return;
}
void Launcher::SettingsPage::on_browseButton_clicked()
{
QString iniFile = QFileDialog::getOpenFileName(
this,
QObject::tr("Select configuration file"),
QDir::currentPath(),
QString(tr("Morrowind configuration file (*.ini)")));
if (iniFile.isEmpty())
return;
QFileInfo info(iniFile);
if (!info.exists() || !info.isReadable())
return;
const QString path(QDir::toNativeSeparators(info.absoluteFilePath()));
if (settingsComboBox->findText(path) == -1) {
settingsComboBox->addItem(path);
settingsComboBox->setCurrentIndex(settingsComboBox->findText(path));
importerButton->setEnabled(true);
}
}
void Launcher::SettingsPage::wizardStarted()
{
mMain->hide(); // Hide the launcher
wizardButton->setEnabled(false);
}
void Launcher::SettingsPage::wizardFinished(int exitCode, QProcess::ExitStatus exitStatus)
{
if (exitCode != 0 || exitStatus == QProcess::CrashExit)
return qApp->quit();
mMain->reloadSettings();
wizardButton->setEnabled(true);
mMain->show(); // Show the launcher again
}
void Launcher::SettingsPage::importerStarted()
{
importerButton->setEnabled(false);
}
void Launcher::SettingsPage::importerFinished(int exitCode, QProcess::ExitStatus exitStatus)
{
if (exitCode != 0 || exitStatus == QProcess::CrashExit)
return;
// Re-read the settings in their current state
mMain->reloadSettings();
// Import selected data files from openmw.cfg
if (addonsCheckBox->isChecked())
{
if (mProfileDialog->exec() == QDialog::Accepted)
{
const QString profile(mProfileDialog->lineEdit()->text());
const QStringList files(mGameSettings.values(QLatin1String("content")));
qDebug() << "Profile " << profile << files;
// Doesn't quite work right now
mLauncherSettings.setValue(QLatin1String("Profiles/currentprofile"), profile);
foreach (const QString &file, files) {
mLauncherSettings.setMultiValue(QLatin1String("Profiles/") + profile + QLatin1String("/content"), file);
}
mGameSettings.remove(QLatin1String("content"));
}
}
mMain->reloadSettings();
importerButton->setEnabled(true);
}
void Launcher::SettingsPage::updateOkButton(const QString &text)
{
// We do this here because we need to access the profiles
if (text.isEmpty()) {
mProfileDialog->setOkButtonEnabled(false);
return;
}
const QStringList profiles(mLauncherSettings.subKeys(QString("Profiles/")));
(profiles.contains(text))
? mProfileDialog->setOkButtonEnabled(false)
: mProfileDialog->setOkButtonEnabled(true);
}
void Launcher::SettingsPage::saveSettings()
{
QString language(languageComboBox->currentText());
mLauncherSettings.setValue(QLatin1String("Settings/language"), language);
if (language == QLatin1String("Polish")) {
mGameSettings.setValue(QLatin1String("encoding"), QLatin1String("win1250"));
} else if (language == QLatin1String("Russian")) {
mGameSettings.setValue(QLatin1String("encoding"), QLatin1String("win1251"));
} else {
mGameSettings.setValue(QLatin1String("encoding"), QLatin1String("win1252"));
}
}
bool Launcher::SettingsPage::loadSettings()
{
QString language(mLauncherSettings.value(QLatin1String("Settings/language")));
int index = languageComboBox->findText(language);
if (index != -1)
languageComboBox->setCurrentIndex(index);
return true;
}

View file

@ -0,0 +1,64 @@
#ifndef SETTINGSPAGE_HPP
#define SETTINGSPAGE_HPP
#include <QWidget>
#include <QProcess>
#include <components/process/processinvoker.hpp>
#include "ui_settingspage.h"
#include "maindialog.hpp"
namespace Files { struct ConfigurationManager; }
namespace Config { class GameSettings;
class LauncherSettings; }
namespace Launcher
{
class TextInputDialog;
class SettingsPage : public QWidget, private Ui::SettingsPage
{
Q_OBJECT
public:
SettingsPage(Files::ConfigurationManager &cfg, Config::GameSettings &gameSettings,
Config::LauncherSettings &launcherSettings, MainDialog *parent = 0);
~SettingsPage();
void saveSettings();
bool loadSettings();
private slots:
void on_wizardButton_clicked();
void on_importerButton_clicked();
void on_browseButton_clicked();
void wizardStarted();
void wizardFinished(int exitCode, QProcess::ExitStatus exitStatus);
void importerStarted();
void importerFinished(int exitCode, QProcess::ExitStatus exitStatus);
void updateOkButton(const QString &text);
private:
Process::ProcessInvoker *mWizardInvoker;
Process::ProcessInvoker *mImporterInvoker;
Files::ConfigurationManager &mCfgMgr;
Config::GameSettings &mGameSettings;
Config::LauncherSettings &mLauncherSettings;
MainDialog *mMain;
TextInputDialog *mProfileDialog;
};
}
#endif // SETTINGSPAGE_HPP

View file

@ -1,521 +0,0 @@
#include "unshieldthread.hpp"
#include <boost/filesystem/fstream.hpp>
#include <components/misc/stringops.hpp>
namespace bfs = boost::filesystem;
namespace
{
static bool make_sure_directory_exists(bfs::path directory)
{
if(!bfs::exists(directory))
{
bfs::create_directories(directory);
}
return bfs::exists(directory);
}
void fill_path(bfs::path& path, const std::string& name)
{
size_t start = 0;
size_t i;
for(i = 0; i < name.length(); i++)
{
switch(name[i])
{
case '\\':
path /= name.substr(start, i-start);
start = i+1;
break;
}
}
path /= name.substr(start, i-start);
}
std::string get_setting(const std::string& category, const std::string& setting, const std::string& inx)
{
size_t start = inx.find(category);
start = inx.find(setting, start) + setting.length() + 3;
size_t end = inx.find("!", start);
return inx.substr(start, end-start);
}
std::string read_to_string(const bfs::path& path)
{
bfs::ifstream strstream(path, std::ios::in | std::ios::binary);
std::string str;
strstream.seekg(0, std::ios::end);
str.resize(strstream.tellg());
strstream.seekg(0, std::ios::beg);
strstream.read(&str[0], str.size());
strstream.close();
return str;
}
void add_setting(const std::string& category, const std::string& setting, const std::string& val, std::string& ini)
{
size_t loc;
loc = ini.find("[" + category + "]");
// If category is not found, create it
if(loc == std::string::npos)
{
loc = ini.size() + 2;
ini += ("\r\n[" + category + "]\r\n");
}
loc += category.length() +2 +2;
ini.insert(loc, setting + "=" + val + "\r\n");
}
#define FIX(setting) add_setting(category, setting, get_setting(category, setting, inx), ini)
void bloodmoon_fix_ini(std::string& ini, const bfs::path inxPath)
{
std::string inx = read_to_string(inxPath);
// Remove this one setting (the only one actually changed by bloodmoon, as opposed to just adding new ones)
size_t start = ini.find("[Weather Blight]");
start = ini.find("Ambient Loop Sound ID", start);
size_t end = ini.find("\r\n", start) +2;
ini.erase(start, end-start);
std::string category;
category = "General";
{
FIX("Werewolf FOV");
}
category = "Moons";
{
FIX("Script Color");
}
category = "Weather";
{
FIX("Snow Ripples");
FIX("Snow Ripple Radius");
FIX("Snow Ripples Per Flake");
FIX("Snow Ripple Scale");
FIX("Snow Ripple Speed");
FIX("Snow Gravity Scale");
FIX("Snow High Kill");
FIX("Snow Low Kill");
}
category = "Weather Blight";
{
FIX("Ambient Loop Sound ID");
}
category = "Weather Snow";
{
FIX("Sky Sunrise Color");
FIX("Sky Day Color");
FIX("Sky Sunset Color");
FIX("Sky Night Color");
FIX("Fog Sunrise Color");
FIX("Fog Day Color");
FIX("Fog Sunset Color");
FIX("Fog Night Color");
FIX("Ambient Sunrise Color");
FIX("Ambient Day Color");
FIX("Ambient Sunset Color");
FIX("Ambient Night Color");
FIX("Sun Sunrise Color");
FIX("Sun Day Color");
FIX("Sun Sunset Color");
FIX("Sun Night Color");
FIX("Sun Disc Sunset Color");
FIX("Transition Delta");
FIX("Land Fog Day Depth");
FIX("Land Fog Night Depth");
FIX("Clouds Maximum Percent");
FIX("Wind Speed");
FIX("Cloud Speed");
FIX("Glare View");
FIX("Cloud Texture");
FIX("Ambient Loop Sound ID");
FIX("Snow Threshold");
FIX("Snow Diameter");
FIX("Snow Height Min");
FIX("Snow Height Max");
FIX("Snow Entrance Speed");
FIX("Max Snowflakes");
}
category = "Weather Blizzard";
{
FIX("Sky Sunrise Color");
FIX("Sky Day Color");
FIX("Sky Sunset Color");
FIX("Sky Night Color");
FIX("Fog Sunrise Color");
FIX("Fog Day Color");
FIX("Fog Sunset Color");
FIX("Fog Night Color");
FIX("Ambient Sunrise Color");
FIX("Ambient Day Color");
FIX("Ambient Sunset Color");
FIX("Ambient Night Color");
FIX("Sun Sunrise Color");
FIX("Sun Day Color");
FIX("Sun Sunset Color");
FIX("Sun Night Color");
FIX("Sun Disc Sunset Color");
FIX("Transition Delta");
FIX("Land Fog Day Depth");
FIX("Land Fog Night Depth");
FIX("Clouds Maximum Percent");
FIX("Wind Speed");
FIX("Cloud Speed");
FIX("Glare View");
FIX("Cloud Texture");
FIX("Ambient Loop Sound ID");
FIX("Storm Threshold");
}
}
void fix_ini(const bfs::path& output_dir, bfs::path cdPath, bool tribunal, bool bloodmoon)
{
bfs::path ini_path = output_dir;
ini_path /= "Morrowind.ini";
std::string ini = read_to_string(ini_path.string());
if(tribunal)
{
add_setting("Game Files", "GameFile1", "Tribunal.esm", ini);
add_setting("Archives", "Archive 0", "Tribunal.bsa", ini);
}
if(bloodmoon)
{
bloodmoon_fix_ini(ini, cdPath / "setup.inx");
add_setting("Game Files", "GameFile2", "Bloodmoon.esm", ini);
add_setting("Archives", "Archive 1", "Bloodmoon.bsa", ini);
}
bfs::ofstream inistream((ini_path));
inistream << ini;
inistream.close();
}
void installToPath(const bfs::path& from, const bfs::path& to, bool copy = false)
{
make_sure_directory_exists(to);
for ( bfs::directory_iterator end, dir(from); dir != end; ++dir )
{
if(bfs::is_directory(dir->path()))
installToPath(dir->path(), to / dir->path().filename(), copy);
else
{
if(copy)
{
bfs::path dest = to / dir->path().filename();
if(bfs::exists(dest))
bfs::remove_all(dest);
bfs::copy_file(dir->path(), dest);
}
else
bfs::rename(dir->path(), to / dir->path().filename());
}
}
}
bfs::path findFile(const bfs::path& in, std::string filename, bool recursive = true)
{
if(recursive)
{
for ( bfs::recursive_directory_iterator end, dir(in); dir != end; ++dir )
{
if(Misc::StringUtils::ciEqual(dir->path().filename().string(), filename))
return dir->path();
}
}
else
{
for ( bfs::directory_iterator end, dir(in); dir != end; ++dir )
{
if(Misc::StringUtils::ciEqual(dir->path().filename().string(), filename))
return dir->path();
}
}
return "";
}
bool contains(const bfs::path& in, std::string filename)
{
for(bfs::directory_iterator end, dir(in); dir != end; ++dir)
{
if(Misc::StringUtils::ciEqual(dir->path().filename().string(), filename))
return true;
}
return false;
}
time_t getTime(const char* time)
{
struct tm tms;
memset(&tms, 0, sizeof(struct tm));
strptime(time, "%d %B %Y", &tms);
return mktime(&tms);
}
// Some cds have cab files which have the Data Files subfolders outside the Data Files folder
void install_dfiles_outside(const bfs::path& from, const bfs::path& dFiles)
{
bfs::path fonts = findFile(from, "fonts", false);
if(fonts.string() != "")
installToPath(fonts, dFiles / "Fonts");
bfs::path music = findFile(from, "music", false);
if(music.string() != "")
installToPath(music, dFiles / "Music");
bfs::path sound = findFile(from, "sound", false);
if(sound.string() != "")
installToPath(sound, dFiles / "Sound");
bfs::path splash = findFile(from, "splash", false);
if(splash.string() != "")
installToPath(splash, dFiles / "Splash");
}
}
bool Launcher::UnshieldThread::SetMorrowindPath(const std::string& path)
{
mMorrowindPath = path;
return true;
}
bool Launcher::UnshieldThread::SetTribunalPath(const std::string& path)
{
mTribunalPath = path;
return true;
}
bool Launcher::UnshieldThread::SetBloodmoonPath(const std::string& path)
{
mBloodmoonPath = path;
return true;
}
void Launcher::UnshieldThread::SetOutputPath(const std::string& path)
{
mOutputPath = path;
}
bool Launcher::UnshieldThread::extract_file(Unshield* unshield, bfs::path output_dir, const char* prefix, int index)
{
bool success;
bfs::path dirname;
bfs::path filename;
int directory = unshield_file_directory(unshield, index);
dirname = output_dir;
if (prefix && prefix[0])
dirname /= prefix;
if (directory >= 0)
{
const char* tmp = unshield_directory_name(unshield, directory);
if (tmp && tmp[0])
fill_path(dirname, tmp);
}
make_sure_directory_exists(dirname);
filename = dirname;
filename /= unshield_file_name(unshield, index);
emit signalGUI(QString("Extracting: ") + QString(filename.c_str()));
success = unshield_file_save(unshield, index, filename.c_str());
if (!success)
bfs::remove(filename);
return success;
}
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());
int i;
for (i = 0; i < unshield_file_group_count(unshield); i++)
{
UnshieldFileGroup* file_group = unshield_file_group_get(unshield, i);
for (size_t j = file_group->first_file; j <= file_group->last_file; j++)
{
if (unshield_file_is_valid(unshield, j))
extract_file(unshield, output_dir, file_group->name, j);
}
}
unshield_close(unshield);
}
bool Launcher::UnshieldThread::extract()
{
bfs::path outputDataFilesDir = mOutputPath;
outputDataFilesDir /= "Data Files";
bfs::path extractPath = mOutputPath;
extractPath /= "extract-temp";
if(!mMorrowindDone && mMorrowindPath.string().length() > 0)
{
mMorrowindDone = true;
bfs::path mwExtractPath = extractPath / "morrowind";
extract_cab(mMorrowindPath, mwExtractPath, true);
bfs::path dFilesDir = findFile(mwExtractPath, "morrowind.esm").parent_path();
installToPath(dFilesDir, outputDataFilesDir);
install_dfiles_outside(mwExtractPath, outputDataFilesDir);
// Videos are often kept uncompressed on the cd
bfs::path videosPath = findFile(mMorrowindPath.parent_path(), "video", false);
if(videosPath.string() != "")
{
emit signalGUI(QString("Installing Videos..."));
installToPath(videosPath, outputDataFilesDir / "Video", true);
}
bfs::path cdDFiles = findFile(mMorrowindPath.parent_path(), "data files", false);
if(cdDFiles.string() != "")
{
emit signalGUI(QString("Installing Uncompressed Data files from CD..."));
installToPath(cdDFiles, outputDataFilesDir, true);
}
bfs::rename(findFile(mwExtractPath, "morrowind.ini"), outputDataFilesDir / "Morrowind.ini");
mTribunalDone = contains(outputDataFilesDir, "tribunal.esm");
mBloodmoonDone = contains(outputDataFilesDir, "bloodmoon.esm");
}
else if(!mTribunalDone && mTribunalPath.string().length() > 0)
{
mTribunalDone = true;
bfs::path tbExtractPath = extractPath / "tribunal";
extract_cab(mTribunalPath, tbExtractPath, true);
bfs::path dFilesDir = findFile(tbExtractPath, "tribunal.esm").parent_path();
installToPath(dFilesDir, outputDataFilesDir);
install_dfiles_outside(tbExtractPath, outputDataFilesDir);
// Mt GOTY CD has Sounds in a seperate folder from the rest of the data files
bfs::path soundsPath = findFile(tbExtractPath, "sounds", false);
if(soundsPath.string() != "")
installToPath(soundsPath, outputDataFilesDir / "Sounds");
bfs::path cdDFiles = findFile(mTribunalPath.parent_path(), "data files", false);
if(cdDFiles.string() != "")
{
emit signalGUI(QString("Installing Uncompressed Data files from CD..."));
installToPath(cdDFiles, outputDataFilesDir, true);
}
mBloodmoonDone = contains(outputDataFilesDir, "bloodmoon.esm");
fix_ini(outputDataFilesDir, bfs::path(mTribunalPath).parent_path(), mTribunalDone, mBloodmoonDone);
}
else if(!mBloodmoonDone && mBloodmoonPath.string().length() > 0)
{
mBloodmoonDone = true;
bfs::path bmExtractPath = extractPath / "bloodmoon";
extract_cab(mBloodmoonPath, bmExtractPath, true);
bfs::path dFilesDir = findFile(bmExtractPath, "bloodmoon.esm").parent_path();
installToPath(dFilesDir, outputDataFilesDir);
install_dfiles_outside(bmExtractPath, outputDataFilesDir);
// My GOTY CD contains a folder within cab files called Tribunal patch,
// which contains Tribunal.esm
bfs::path tbPatchPath = findFile(bmExtractPath, "tribunal.esm");
if(tbPatchPath.string() != "")
bfs::rename(tbPatchPath, outputDataFilesDir / "Tribunal.esm");
bfs::path cdDFiles = findFile(mBloodmoonPath.parent_path(), "data files", false);
if(cdDFiles.string() != "")
{
emit signalGUI(QString("Installing Uncompressed Data files from CD..."));
installToPath(cdDFiles, outputDataFilesDir, true);
}
fix_ini(outputDataFilesDir, bfs::path(mBloodmoonPath).parent_path(), false, mBloodmoonDone);
}
return true;
}
void Launcher::UnshieldThread::Done()
{
// Get rid of unnecessary files
bfs::remove_all(mOutputPath / "extract-temp");
// Set modified time to release dates, to preserve load order
if(mMorrowindDone)
bfs::last_write_time(findFile(mOutputPath, "morrowind.esm"), getTime("1 May 2002"));
if(mTribunalDone)
bfs::last_write_time(findFile(mOutputPath, "tribunal.esm"), getTime("6 November 2002"));
if(mBloodmoonDone)
bfs::last_write_time(findFile(mOutputPath, "bloodmoon.esm"), getTime("3 June 2003"));
}
std::string Launcher::UnshieldThread::GetMWEsmPath()
{
return findFile(mOutputPath / "Data Files", "morrowind.esm").string();
}
bool Launcher::UnshieldThread::TribunalDone()
{
return mTribunalDone;
}
bool Launcher::UnshieldThread::BloodmoonDone()
{
return mBloodmoonDone;
}
void Launcher::UnshieldThread::run()
{
extract();
emit close();
}
Launcher::UnshieldThread::UnshieldThread()
{
unshield_set_log_level(0);
mMorrowindDone = false;
mTribunalDone = false;
mBloodmoonDone = false;
}

View file

@ -1,58 +0,0 @@
#ifndef UNSHIELD_THREAD_H
#define UNSHIELD_THREAD_H
#include <QThread>
#include <boost/filesystem.hpp>
#include <libunshield.h>
namespace Launcher
{
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);
void SetOutputPath(const std::string& path);
bool extract();
bool TribunalDone();
bool BloodmoonDone();
void Done();
std::string GetMWEsmPath();
UnshieldThread();
private:
void extract_cab(const boost::filesystem::path& cab, const boost::filesystem::path& output_dir, bool extract_ini = false);
bool extract_file(Unshield* unshield, boost::filesystem::path output_dir, const char* prefix, int index);
boost::filesystem::path mMorrowindPath;
boost::filesystem::path mTribunalPath;
boost::filesystem::path mBloodmoonPath;
bool mMorrowindDone;
bool mTribunalDone;
bool mBloodmoonDone;
boost::filesystem::path mOutputPath;
protected:
virtual void run();
signals:
void signalGUI(QString);
void close();
};
}
#endif

View file

@ -1,258 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia. For licensing terms and
** conditions see http://qt.digia.com/licensing. For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights. These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/
#include "checkablemessagebox.hpp"
#include <QVariant>
#include <QPushButton>
#include <QAction>
#include <QApplication>
#include <QButtonGroup>
#include <QCheckBox>
#include <QDialog>
#include <QDialogButtonBox>
#include <QHBoxLayout>
#include <QHeaderView>
#include <QLabel>
#include <QSpacerItem>
#include <QVBoxLayout>
/*!
\class Utils::CheckableMessageBox
\brief A messagebox suitable for questions with a
"Do not ask me again" checkbox.
Emulates the QMessageBox API with
static conveniences. The message label can open external URLs.
*/
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(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);
}
Launcher::CheckableMessageBox::CheckableMessageBox(QWidget *parent) :
QDialog(parent),
d(new Launcher::CheckableMessageBoxPrivate(this))
{
setModal(true);
setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
connect(d->buttonBox, SIGNAL(accepted()), SLOT(accept()));
connect(d->buttonBox, SIGNAL(rejected()), SLOT(reject()));
connect(d->buttonBox, SIGNAL(clicked(QAbstractButton*)),
SLOT(slotClicked(QAbstractButton*)));
}
Launcher::CheckableMessageBox::~CheckableMessageBox()
{
delete d;
}
void Launcher::CheckableMessageBox::slotClicked(QAbstractButton *b)
{
d->clickedButton = b;
}
QAbstractButton *Launcher::CheckableMessageBox::clickedButton() const
{
return d->clickedButton;
}
QDialogButtonBox::StandardButton Launcher::CheckableMessageBox::clickedStandardButton() const
{
if (d->clickedButton)
return d->buttonBox->standardButton(d->clickedButton);
return QDialogButtonBox::NoButton;
}
QString Launcher::CheckableMessageBox::text() const
{
return d->messageLabel->text();
}
void Launcher::CheckableMessageBox::setText(const QString &t)
{
d->messageLabel->setText(t);
}
QPixmap Launcher::CheckableMessageBox::iconPixmap() const
{
if (const QPixmap *p = d->pixmapLabel->pixmap())
return QPixmap(*p);
return QPixmap();
}
void Launcher::CheckableMessageBox::setIconPixmap(const QPixmap &p)
{
d->pixmapLabel->setPixmap(p);
d->pixmapLabel->setVisible(!p.isNull());
}
bool Launcher::CheckableMessageBox::isChecked() const
{
return d->checkBox->isChecked();
}
void Launcher::CheckableMessageBox::setChecked(bool s)
{
d->checkBox->setChecked(s);
}
QString Launcher::CheckableMessageBox::checkBoxText() const
{
return d->checkBox->text();
}
void Launcher::CheckableMessageBox::setCheckBoxText(const QString &t)
{
d->checkBox->setText(t);
}
bool Launcher::CheckableMessageBox::isCheckBoxVisible() const
{
return d->checkBox->isVisible();
}
void Launcher::CheckableMessageBox::setCheckBoxVisible(bool v)
{
d->checkBox->setVisible(v);
}
QDialogButtonBox::StandardButtons Launcher::CheckableMessageBox::standardButtons() const
{
return d->buttonBox->standardButtons();
}
void Launcher::CheckableMessageBox::setStandardButtons(QDialogButtonBox::StandardButtons s)
{
d->buttonBox->setStandardButtons(s);
}
QPushButton *Launcher::CheckableMessageBox::button(QDialogButtonBox::StandardButton b) const
{
return d->buttonBox->button(b);
}
QPushButton *Launcher::CheckableMessageBox::addButton(const QString &text, QDialogButtonBox::ButtonRole role)
{
return d->buttonBox->addButton(text, role);
}
QDialogButtonBox::StandardButton Launcher::CheckableMessageBox::defaultButton() const
{
foreach (QAbstractButton *b, d->buttonBox->buttons())
if (QPushButton *pb = qobject_cast<QPushButton *>(b))
if (pb->isDefault())
return d->buttonBox->standardButton(pb);
return QDialogButtonBox::NoButton;
}
void Launcher::CheckableMessageBox::setDefaultButton(QDialogButtonBox::StandardButton s)
{
if (QPushButton *b = d->buttonBox->button(s)) {
b->setDefault(true);
b->setFocus();
}
}
QDialogButtonBox::StandardButton
Launcher::CheckableMessageBox::question(QWidget *parent,
const QString &title,
const QString &question,
const QString &checkBoxText,
bool *checkBoxSetting,
QDialogButtonBox::StandardButtons buttons,
QDialogButtonBox::StandardButton defaultButton)
{
CheckableMessageBox mb(parent);
mb.setWindowTitle(title);
mb.setIconPixmap(QMessageBox::standardIcon(QMessageBox::Question));
mb.setText(question);
mb.setCheckBoxText(checkBoxText);
mb.setChecked(*checkBoxSetting);
mb.setStandardButtons(buttons);
mb.setDefaultButton(defaultButton);
mb.exec();
*checkBoxSetting = mb.isChecked();
return mb.clickedStandardButton();
}
QMessageBox::StandardButton Launcher::CheckableMessageBox::dialogButtonBoxToMessageBoxButton(QDialogButtonBox::StandardButton db)
{
return static_cast<QMessageBox::StandardButton>(int(db));
}

View file

@ -1,116 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia. For licensing terms and
** conditions see http://qt.digia.com/licensing. For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights. These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/
#ifndef CHECKABLEMESSAGEBOX_HPP
#define CHECKABLEMESSAGEBOX_HPP
#include <QDialogButtonBox>
#include <QMessageBox>
#include <QDialog>
class QCheckBox;
namespace Launcher
{
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

View file

@ -47,13 +47,13 @@ void ProfilesComboBox::setEditEnabled(bool editable)
void ProfilesComboBox::slotTextChanged(const QString &text) void ProfilesComboBox::slotTextChanged(const QString &text)
{ {
QPalette *palette = new QPalette(); QPalette palette;
palette->setColor(QPalette::Text,Qt::red); palette.setColor(QPalette::Text,Qt::red);
int index = findText(text); int index = findText(text);
if (text.isEmpty() || (index != -1 && index != currentIndex())) { if (text.isEmpty() || (index != -1 && index != currentIndex())) {
lineEdit()->setPalette(*palette); lineEdit()->setPalette(palette);
} else { } else {
lineEdit()->setPalette(QApplication::palette()); lineEdit()->setPalette(QApplication::palette());
} }

View file

@ -16,15 +16,15 @@ Launcher::TextInputDialog::TextInputDialog(const QString& title, const QString &
mButtonBox->addButton(QDialogButtonBox::Cancel); mButtonBox->addButton(QDialogButtonBox::Cancel);
mButtonBox->button(QDialogButtonBox::Ok)->setEnabled (false); mButtonBox->button(QDialogButtonBox::Ok)->setEnabled (false);
// Line edit
QValidator *validator = new QRegExpValidator(QRegExp("^[a-zA-Z0-9_]*$"), this); // Alpha-numeric + underscore
mLineEdit = new DialogLineEdit(this);
mLineEdit->setValidator(validator);
mLineEdit->setCompleter(0);
QLabel *label = new QLabel(this); QLabel *label = new QLabel(this);
label->setText(text); label->setText(text);
// Line edit
QValidator *validator = new QRegExpValidator(QRegExp("^[a-zA-Z0-9_]*$"), this); // Alpha-numeric + underscore
mLineEdit = new LineEdit(this);
mLineEdit->setValidator(validator);
mLineEdit->setCompleter(0);
QVBoxLayout *dialogLayout = new QVBoxLayout(this); QVBoxLayout *dialogLayout = new QVBoxLayout(this);
dialogLayout->addWidget(label); dialogLayout->addWidget(label);
dialogLayout->addWidget(mLineEdit); dialogLayout->addWidget(mLineEdit);
@ -41,8 +41,10 @@ Launcher::TextInputDialog::TextInputDialog(const QString& title, const QString &
connect(mButtonBox, SIGNAL(accepted()), this, SLOT(accept())); connect(mButtonBox, SIGNAL(accepted()), this, SLOT(accept()));
connect(mButtonBox, SIGNAL(rejected()), this, SLOT(reject())); connect(mButtonBox, SIGNAL(rejected()), this, SLOT(reject()));
connect(mLineEdit, SIGNAL(textChanged(QString)), this, SLOT(slotUpdateOkButton(QString))); }
Launcher::TextInputDialog::~TextInputDialog()
{
} }
int Launcher::TextInputDialog::exec() int Launcher::TextInputDialog::exec()
@ -52,36 +54,18 @@ int Launcher::TextInputDialog::exec()
return QDialog::exec(); return QDialog::exec();
} }
QString Launcher::TextInputDialog::getText() const void Launcher::TextInputDialog::setOkButtonEnabled(bool enabled)
{ {
return mLineEdit->text(); QPushButton *okButton = mButtonBox->button(QDialogButtonBox::Ok);
} okButton->setEnabled(enabled);
void Launcher::TextInputDialog::slotUpdateOkButton(QString text) QPalette palette;
{ palette.setColor(QPalette::Text, Qt::red);
bool enabled = !(text.isEmpty());
mButtonBox->button(QDialogButtonBox::Ok)->setEnabled(enabled);
if (enabled) if (enabled) {
mLineEdit->setPalette(QApplication::palette()); mLineEdit->setPalette(QApplication::palette());
else } else {
{
// Existing profile name, make the text red // Existing profile name, make the text red
QPalette *palette = new QPalette(); mLineEdit->setPalette(palette);
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));
}

View file

@ -13,26 +13,20 @@ namespace Launcher
{ {
Q_OBJECT Q_OBJECT
class DialogLineEdit : public LineEdit
{
public:
explicit DialogLineEdit (QWidget *parent = 0);
};
DialogLineEdit *mLineEdit;
QDialogButtonBox *mButtonBox;
public: public:
explicit TextInputDialog(const QString& title, const QString &text, QWidget *parent = 0); explicit TextInputDialog(const QString& title, const QString &text, QWidget *parent = 0);
~TextInputDialog () {} ~TextInputDialog ();
QString getText() const; inline LineEdit *lineEdit() { return mLineEdit; }
void setOkButtonEnabled(bool enabled);
int exec(); int exec();
private slots: private:
void slotUpdateOkButton(QString text);
QDialogButtonBox *mButtonBox;
LineEdit *mLineEdit;
}; };
} }

View file

@ -11,7 +11,7 @@ opencs_units (model/doc
) )
opencs_units_noqt (model/doc opencs_units_noqt (model/doc
stage savingstate savingstages blacklist stage savingstate savingstages blacklist messages
) )
opencs_hdrs_noqt (model/doc opencs_hdrs_noqt (model/doc
@ -68,16 +68,17 @@ opencs_units (view/world
opencs_units_noqt (view/world opencs_units_noqt (view/world
subviews enumdelegate vartypedelegate recordstatusdelegate idtypedelegate datadisplaydelegate subviews enumdelegate vartypedelegate recordstatusdelegate idtypedelegate datadisplaydelegate
scripthighlighter idvalidator dialoguecreator physicssystem physicsmanager scripthighlighter idvalidator dialoguecreator physicssystem
) )
opencs_units (view/widget opencs_units (view/widget
scenetoolbar scenetool scenetoolmode pushbutton scenetooltoggle scenetoolrun scenetoolbar scenetool scenetoolmode pushbutton scenetooltoggle scenetoolrun modebutton
scenetooltoggle2
) )
opencs_units (view/render opencs_units (view/render
scenewidget worldspacewidget pagedworldspacewidget unpagedworldspacewidget scenewidget worldspacewidget pagedworldspacewidget unpagedworldspacewidget
previewwidget previewwidget editmode
) )
opencs_units_noqt (view/render opencs_units_noqt (view/render
@ -91,7 +92,7 @@ opencs_hdrs_noqt (view/render
opencs_units (view/tools opencs_units (view/tools
reportsubview reportsubview reporttable
) )
opencs_units_noqt (view/tools opencs_units_noqt (view/tools

View file

@ -1,6 +1,8 @@
#include "editor.hpp" #include "editor.hpp"
#include <openengine/bullet/BulletShapeLoader.h>
#include <QApplication> #include <QApplication>
#include <QLocalServer> #include <QLocalServer>
#include <QLocalSocket> #include <QLocalSocket>
@ -21,8 +23,8 @@
CS::Editor::Editor (OgreInit::OgreInit& ogreInit) CS::Editor::Editor (OgreInit::OgreInit& ogreInit)
: mUserSettings (mCfgMgr), mOverlaySystem (0), mDocumentManager (mCfgMgr), : mUserSettings (mCfgMgr), mOverlaySystem (0), mDocumentManager (mCfgMgr),
mViewManager (mDocumentManager), mPhysicsManager (0), mViewManager (mDocumentManager),
mIpcServerName ("org.openmw.OpenCS"), mServer(NULL), mClientSocket(NULL) mIpcServerName ("org.openmw.OpenCS"), mServer(NULL), mClientSocket(NULL), mPid(""), mLock()
{ {
std::pair<Files::PathContainer, std::vector<std::string> > config = readConfig(); std::pair<Files::PathContainer, std::vector<std::string> > config = readConfig();
@ -34,7 +36,6 @@ CS::Editor::Editor (OgreInit::OgreInit& ogreInit)
ogreInit.init ((mCfgMgr.getUserConfigPath() / "opencsOgre.log").string()); ogreInit.init ((mCfgMgr.getUserConfigPath() / "opencsOgre.log").string());
mOverlaySystem.reset (new CSVRender::OverlaySystem); mOverlaySystem.reset (new CSVRender::OverlaySystem);
mPhysicsManager.reset (new CSVWorld::PhysicsManager);
Bsa::registerResources (Files::Collections (config.first, !mFsStrict), config.second, true, Bsa::registerResources (Files::Collections (config.first, !mFsStrict), config.second, true,
mFsStrict); mFsStrict);
@ -70,7 +71,15 @@ CS::Editor::Editor (OgreInit::OgreInit& ogreInit)
} }
CS::Editor::~Editor () CS::Editor::~Editor ()
{} {
mPidFile.close();
if(mServer && boost::filesystem::exists(mPid))
remove(mPid.string().c_str()); // ignore any error
// cleanup global resources used by OEngine
delete OEngine::Physic::BulletShapeManager::getSingletonPtr();
}
void CS::Editor::setupDataFiles (const Files::PathContainer& dataDirs) void CS::Editor::setupDataFiles (const Files::PathContainer& dataDirs)
{ {
@ -233,8 +242,54 @@ void CS::Editor::showSettings()
bool CS::Editor::makeIPCServer() bool CS::Editor::makeIPCServer()
{ {
try
{
mPid = boost::filesystem::temp_directory_path();
mPid /= "opencs.pid";
bool pidExists = boost::filesystem::exists(mPid);
mPidFile.open(mPid);
mLock = boost::interprocess::file_lock(mPid.string().c_str());
if(!mLock.try_lock())
{
std::cerr << "OpenCS already running." << std::endl;
return false;
}
#ifdef _WIN32
mPidFile << GetCurrentProcessId() << std::endl;
#else
mPidFile << getpid() << std::endl;
#endif
mServer = new QLocalServer(this); mServer = new QLocalServer(this);
if(pidExists)
{
// hack to get the temp directory path
mServer->listen("dummy");
QString fullPath = mServer->fullServerName();
mServer->close();
fullPath.remove(QRegExp("dummy$"));
fullPath += mIpcServerName;
if(boost::filesystem::exists(fullPath.toStdString().c_str()))
{
// TODO: compare pid of the current process with that in the file
std::cout << "Detected unclean shutdown." << std::endl;
// delete the stale file
if(remove(fullPath.toStdString().c_str()))
std::cerr << "ERROR removing stale connection file" << std::endl;
}
}
}
catch(const std::exception& e)
{
std::cerr << "ERROR " << e.what() << std::endl;
return false;
}
if(mServer->listen(mIpcServerName)) if(mServer->listen(mIpcServerName))
{ {
connect(mServer, SIGNAL(newConnection()), this, SLOT(showStartup())); connect(mServer, SIGNAL(newConnection()), this, SLOT(showStartup()));
@ -242,6 +297,7 @@ bool CS::Editor::makeIPCServer()
} }
mServer->close(); mServer->close();
mServer = NULL;
return false; return false;
} }
@ -379,5 +435,5 @@ void CS::Editor::documentAdded (CSMDoc::Document *document)
void CS::Editor::lastDocumentDeleted() void CS::Editor::lastDocumentDeleted()
{ {
exit (0); QApplication::quit();
} }

View file

@ -3,6 +3,9 @@
#include <memory> #include <memory>
#include <boost/interprocess/sync/file_lock.hpp>
#include <boost/filesystem/fstream.hpp>
#include <QObject> #include <QObject>
#include <QString> #include <QString>
#include <QLocalServer> #include <QLocalServer>
@ -28,7 +31,6 @@
#include "view/settings/dialog.hpp" #include "view/settings/dialog.hpp"
#include "view/render/overlaysystem.hpp" #include "view/render/overlaysystem.hpp"
#include "view/world/physicsmanager.hpp"
namespace OgreInit namespace OgreInit
{ {
@ -45,7 +47,6 @@ namespace CS
Files::ConfigurationManager mCfgMgr; Files::ConfigurationManager mCfgMgr;
CSMSettings::UserSettings mUserSettings; CSMSettings::UserSettings mUserSettings;
std::auto_ptr<CSVRender::OverlaySystem> mOverlaySystem; std::auto_ptr<CSVRender::OverlaySystem> mOverlaySystem;
std::auto_ptr<CSVWorld::PhysicsManager> mPhysicsManager;
CSMDoc::DocumentManager mDocumentManager; CSMDoc::DocumentManager mDocumentManager;
CSVDoc::ViewManager mViewManager; CSVDoc::ViewManager mViewManager;
CSVDoc::StartupDialogue mStartup; CSVDoc::StartupDialogue mStartup;
@ -54,6 +55,9 @@ namespace CS
CSVDoc::FileDialog mFileDialog; CSVDoc::FileDialog mFileDialog;
boost::filesystem::path mLocal; boost::filesystem::path mLocal;
boost::filesystem::path mResources; boost::filesystem::path mResources;
boost::filesystem::path mPid;
boost::interprocess::file_lock mLock;
boost::filesystem::ofstream mPidFile;
bool mFsStrict; bool mFsStrict;
void setupDataFiles (const Files::PathContainer& dataDirs); void setupDataFiles (const Files::PathContainer& dataDirs);

View file

@ -83,7 +83,7 @@ int main(int argc, char *argv[])
if(!editor.makeIPCServer()) if(!editor.makeIPCServer())
{ {
editor.connectToIPCServer(); editor.connectToIPCServer();
// return 0; return 0;
} }
shinyFactory = editor.setupGraphics(); shinyFactory = editor.setupGraphics();

View file

@ -9,6 +9,8 @@
#include <components/files/configurationmanager.hpp> #include <components/files/configurationmanager.hpp>
#endif #endif
#include "../../view/world/physicssystem.hpp"
void CSMDoc::Document::addGmsts() void CSMDoc::Document::addGmsts()
{ {
static const char *gmstFloats[] = static const char *gmstFloats[] =
@ -2253,7 +2255,7 @@ CSMDoc::Document::Document (const Files::ConfigurationManager& configuration,
mProjectPath ((configuration.getUserDataPath() / "projects") / mProjectPath ((configuration.getUserDataPath() / "projects") /
(savePath.filename().string() + ".project")), (savePath.filename().string() + ".project")),
mSaving (*this, mProjectPath, encoding), mSaving (*this, mProjectPath, encoding),
mRunner (mProjectPath) mRunner (mProjectPath), mPhysics(boost::shared_ptr<CSVWorld::PhysicsSystem>())
{ {
if (mContentFiles.empty()) if (mContentFiles.empty())
throw std::runtime_error ("Empty content file sequence"); throw std::runtime_error ("Empty content file sequence");
@ -2299,8 +2301,8 @@ CSMDoc::Document::Document (const Files::ConfigurationManager& configuration,
connect (&mSaving, SIGNAL (done (int, bool)), this, SLOT (operationDone (int, bool))); connect (&mSaving, SIGNAL (done (int, bool)), this, SLOT (operationDone (int, bool)));
connect ( connect (
&mSaving, SIGNAL (reportMessage (const CSMWorld::UniversalId&, const std::string&, int)), &mSaving, SIGNAL (reportMessage (const CSMWorld::UniversalId&, const std::string&, const std::string&, int)),
this, SLOT (reportMessage (const CSMWorld::UniversalId&, const std::string&, int))); this, SLOT (reportMessage (const CSMWorld::UniversalId&, const std::string&, const std::string&, int)));
connect (&mRunner, SIGNAL (runStateChanged()), this, SLOT (runStateChanged())); connect (&mRunner, SIGNAL (runStateChanged()), this, SLOT (runStateChanged()));
} }
@ -2385,7 +2387,7 @@ void CSMDoc::Document::modificationStateChanged (bool clean)
} }
void CSMDoc::Document::reportMessage (const CSMWorld::UniversalId& id, const std::string& message, void CSMDoc::Document::reportMessage (const CSMWorld::UniversalId& id, const std::string& message,
int type) const std::string& hint, int type)
{ {
/// \todo find a better way to get these messages to the user. /// \todo find a better way to get these messages to the user.
std::cout << message << std::endl; std::cout << message << std::endl;
@ -2464,3 +2466,11 @@ void CSMDoc::Document::progress (int current, int max, int type)
{ {
emit progress (current, max, type, 1, this); emit progress (current, max, type, 1, this);
} }
boost::shared_ptr<CSVWorld::PhysicsSystem> CSMDoc::Document::getPhysics ()
{
if(!mPhysics)
mPhysics = boost::shared_ptr<CSVWorld::PhysicsSystem> (new CSVWorld::PhysicsSystem());
return mPhysics;
}

View file

@ -3,6 +3,7 @@
#include <string> #include <string>
#include <boost/shared_ptr.hpp>
#include <boost/filesystem/path.hpp> #include <boost/filesystem/path.hpp>
#include <QUndoStack> #include <QUndoStack>
@ -39,6 +40,11 @@ namespace CSMWorld
class ResourcesManager; class ResourcesManager;
} }
namespace CSVWorld
{
class PhysicsSystem;
}
namespace CSMDoc namespace CSMDoc
{ {
class Document : public QObject class Document : public QObject
@ -57,6 +63,7 @@ namespace CSMDoc
boost::filesystem::path mResDir; boost::filesystem::path mResDir;
Blacklist mBlacklist; Blacklist mBlacklist;
Runner mRunner; Runner mRunner;
boost::shared_ptr<CSVWorld::PhysicsSystem> mPhysics;
// 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 // 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. // using other member variables. Unfortunately this connection is cut only in the QObject destructor, which is way too late.
@ -129,6 +136,8 @@ namespace CSMDoc
QTextDocument *getRunLog(); QTextDocument *getRunLog();
boost::shared_ptr<CSVWorld::PhysicsSystem> getPhysics();
signals: signals:
void stateChanged (int state, CSMDoc::Document *document); void stateChanged (int state, CSMDoc::Document *document);
@ -140,7 +149,7 @@ namespace CSMDoc
void modificationStateChanged (bool clean); void modificationStateChanged (bool clean);
void reportMessage (const CSMWorld::UniversalId& id, const std::string& message, void reportMessage (const CSMWorld::UniversalId& id, const std::string& message,
int type); const std::string& hint, int type);
void operationDone (int type, bool failed); void operationDone (int type, bool failed);

View file

@ -52,7 +52,7 @@ void CSMDoc::Loader::load()
{ {
if (iter->second.mRecordsLeft) if (iter->second.mRecordsLeft)
{ {
CSMDoc::Stage::Messages messages; CSMDoc::Messages messages;
for (int i=0; i<batchingSize; ++i) // do not flood the system with update signals for (int i=0; i<batchingSize; ++i) // do not flood the system with update signals
if (document->getData().continueLoading (messages)) if (document->getData().continueLoading (messages))
{ {
@ -65,11 +65,11 @@ void CSMDoc::Loader::load()
CSMWorld::UniversalId log (CSMWorld::UniversalId::Type_LoadErrorLog, 0); CSMWorld::UniversalId log (CSMWorld::UniversalId::Type_LoadErrorLog, 0);
{ // silence a g++ warning { // silence a g++ warning
for (CSMDoc::Stage::Messages::const_iterator iter (messages.begin()); for (CSMDoc::Messages::Iterator iter (messages.begin());
iter!=messages.end(); ++iter) iter!=messages.end(); ++iter)
{ {
document->getReport (log)->add (iter->first, iter->second); document->getReport (log)->add (iter->mId, iter->mMessage);
emit loadMessage (document, iter->second); emit loadMessage (document, iter->mMessage);
} }
} }

View file

@ -0,0 +1,28 @@
#include "messages.hpp"
void CSMDoc::Messages::add (const CSMWorld::UniversalId& id, const std::string& message,
const std::string& hint)
{
Message data;
data.mId = id;
data.mMessage = message;
data.mHint = hint;
mMessages.push_back (data);
}
void CSMDoc::Messages::push_back (const std::pair<CSMWorld::UniversalId, std::string>& data)
{
add (data.first, data.second);
}
CSMDoc::Messages::Iterator CSMDoc::Messages::begin() const
{
return mMessages.begin();
}
CSMDoc::Messages::Iterator CSMDoc::Messages::end() const
{
return mMessages.end();
}

View file

@ -0,0 +1,44 @@
#ifndef CSM_DOC_MESSAGES_H
#define CSM_DOC_MESSAGES_H
#include <string>
#include <vector>
#include "../world/universalid.hpp"
namespace CSMDoc
{
class Messages
{
public:
struct Message
{
CSMWorld::UniversalId mId;
std::string mMessage;
std::string mHint;
};
typedef std::vector<Message> Collection;
typedef Collection::const_iterator Iterator;
private:
Collection mMessages;
public:
void add (const CSMWorld::UniversalId& id, const std::string& message,
const std::string& hint = "");
/// \deprecated Use add instead.
void push_back (const std::pair<CSMWorld::UniversalId, std::string>& data);
Iterator begin() const;
Iterator end() const;
};
}
#endif

View file

@ -84,7 +84,7 @@ void CSMDoc::Operation::abort()
void CSMDoc::Operation::executeStage() void CSMDoc::Operation::executeStage()
{ {
Stage::Messages messages; Messages messages;
while (mCurrentStage!=mStages.end()) while (mCurrentStage!=mStages.end())
{ {
@ -101,7 +101,7 @@ void CSMDoc::Operation::executeStage()
} }
catch (const std::exception& e) catch (const std::exception& e)
{ {
emit reportMessage (CSMWorld::UniversalId(), e.what(), mType); emit reportMessage (CSMWorld::UniversalId(), e.what(), "", mType);
abort(); abort();
} }
@ -112,8 +112,8 @@ void CSMDoc::Operation::executeStage()
emit progress (mCurrentStepTotal, mTotalSteps ? mTotalSteps : 1, mType); emit progress (mCurrentStepTotal, mTotalSteps ? mTotalSteps : 1, mType);
for (Stage::Messages::const_iterator iter (messages.begin()); iter!=messages.end(); ++iter) for (Messages::Iterator iter (messages.begin()); iter!=messages.end(); ++iter)
emit reportMessage (iter->first, iter->second, mType); emit reportMessage (iter->mId, iter->mMessage, iter->mHint, mType);
if (mCurrentStage==mStages.end()) if (mCurrentStage==mStages.end())
exit(); exit();

View file

@ -52,7 +52,7 @@ namespace CSMDoc
void progress (int current, int max, int type); void progress (int current, int max, int type);
void reportMessage (const CSMWorld::UniversalId& id, const std::string& message, void reportMessage (const CSMWorld::UniversalId& id, const std::string& message,
int type); const std::string& hint, int type);
void done (int type, bool failed); void done (int type, bool failed);

View file

@ -6,14 +6,14 @@
#include "../world/universalid.hpp" #include "../world/universalid.hpp"
#include "messages.hpp"
namespace CSMDoc namespace CSMDoc
{ {
class Stage class Stage
{ {
public: public:
typedef std::vector<std::pair<CSMWorld::UniversalId, std::string> > Messages;
virtual ~Stage(); virtual ~Stage();
virtual int setup() = 0; virtual int setup() = 0;

View file

@ -17,7 +17,7 @@ int CSMTools::BirthsignCheckStage::setup()
return mBirthsigns.getSize(); return mBirthsigns.getSize();
} }
void CSMTools::BirthsignCheckStage::perform (int stage, Messages& messages) void CSMTools::BirthsignCheckStage::perform (int stage, CSMDoc::Messages& messages)
{ {
const CSMWorld::Record<ESM::BirthSign>& record = mBirthsigns.getRecord (stage); const CSMWorld::Record<ESM::BirthSign>& record = mBirthsigns.getRecord (stage);

View file

@ -21,7 +21,7 @@ namespace CSMTools
virtual int setup(); virtual int setup();
///< \return number of steps ///< \return number of steps
virtual void perform (int stage, Messages& messages); virtual void perform (int stage, CSMDoc::Messages& messages);
///< Messages resulting from this tage will be appended to \a messages. ///< Messages resulting from this tage will be appended to \a messages.
}; };
} }

View file

@ -14,7 +14,7 @@ int CSMTools::BodyPartCheckStage::setup()
return mBodyParts.getSize(); return mBodyParts.getSize();
} }
void CSMTools::BodyPartCheckStage::perform ( int stage, Messages &messages ) void CSMTools::BodyPartCheckStage::perform (int stage, CSMDoc::Messages &messages)
{ {
const CSMWorld::Record<ESM::BodyPart> &record = mBodyParts.getRecord(stage); const CSMWorld::Record<ESM::BodyPart> &record = mBodyParts.getRecord(stage);

View file

@ -27,7 +27,7 @@ namespace CSMTools
virtual int setup(); virtual int setup();
///< \return number of steps ///< \return number of steps
virtual void perform( int stage, Messages &messages ); virtual void perform( int stage, CSMDoc::Messages &messages );
///< Messages resulting from this tage will be appended to \a messages. ///< Messages resulting from this tage will be appended to \a messages.
}; };
} }

View file

@ -18,7 +18,7 @@ int CSMTools::ClassCheckStage::setup()
return mClasses.getSize(); return mClasses.getSize();
} }
void CSMTools::ClassCheckStage::perform (int stage, Messages& messages) void CSMTools::ClassCheckStage::perform (int stage, CSMDoc::Messages& messages)
{ {
const CSMWorld::Record<ESM::Class>& record = mClasses.getRecord (stage); const CSMWorld::Record<ESM::Class>& record = mClasses.getRecord (stage);

View file

@ -21,7 +21,7 @@ namespace CSMTools
virtual int setup(); virtual int setup();
///< \return number of steps ///< \return number of steps
virtual void perform (int stage, Messages& messages); virtual void perform (int stage, CSMDoc::Messages& messages);
///< Messages resulting from this tage will be appended to \a messages. ///< Messages resulting from this tage will be appended to \a messages.
}; };
} }

View file

@ -18,7 +18,7 @@ int CSMTools::FactionCheckStage::setup()
return mFactions.getSize(); return mFactions.getSize();
} }
void CSMTools::FactionCheckStage::perform (int stage, Messages& messages) void CSMTools::FactionCheckStage::perform (int stage, CSMDoc::Messages& messages)
{ {
const CSMWorld::Record<ESM::Faction>& record = mFactions.getRecord (stage); const CSMWorld::Record<ESM::Faction>& record = mFactions.getRecord (stage);

View file

@ -21,7 +21,7 @@ namespace CSMTools
virtual int setup(); virtual int setup();
///< \return number of steps ///< \return number of steps
virtual void perform (int stage, Messages& messages); virtual void perform (int stage, CSMDoc::Messages& messages);
///< Messages resulting from this tage will be appended to \a messages. ///< Messages resulting from this tage will be appended to \a messages.
}; };
} }

View file

@ -15,10 +15,9 @@ int CSMTools::MandatoryIdStage::setup()
return mIds.size(); return mIds.size();
} }
void CSMTools::MandatoryIdStage::perform (int stage, Messages& messages) void CSMTools::MandatoryIdStage::perform (int stage, CSMDoc::Messages& messages)
{ {
if (mIdCollection.searchId (mIds.at (stage))==-1 || if (mIdCollection.searchId (mIds.at (stage))==-1 ||
mIdCollection.getRecord (mIds.at (stage)).isDeleted()) mIdCollection.getRecord (mIds.at (stage)).isDeleted())
messages.push_back (std::make_pair (mCollectionId, messages.add (mCollectionId, "Missing mandatory record: " + mIds.at (stage));
"Missing mandatory record: " + mIds.at (stage)));
} }

View file

@ -30,7 +30,7 @@ namespace CSMTools
virtual int setup(); virtual int setup();
///< \return number of steps ///< \return number of steps
virtual void perform (int stage, Messages& messages); virtual void perform (int stage, CSMDoc::Messages& messages);
///< Messages resulting from this tage will be appended to \a messages. ///< Messages resulting from this tage will be appended to \a messages.
}; };
} }

View file

@ -7,7 +7,7 @@
#include "../world/universalid.hpp" #include "../world/universalid.hpp"
void CSMTools::RaceCheckStage::performPerRecord (int stage, Messages& messages) void CSMTools::RaceCheckStage::performPerRecord (int stage, CSMDoc::Messages& messages)
{ {
const CSMWorld::Record<ESM::Race>& record = mRaces.getRecord (stage); const CSMWorld::Record<ESM::Race>& record = mRaces.getRecord (stage);
@ -46,7 +46,7 @@ void CSMTools::RaceCheckStage::performPerRecord (int stage, Messages& messages)
/// \todo check data members that can't be edited in the table view /// \todo check data members that can't be edited in the table view
} }
void CSMTools::RaceCheckStage::performFinal (Messages& messages) void CSMTools::RaceCheckStage::performFinal (CSMDoc::Messages& messages)
{ {
CSMWorld::UniversalId id (CSMWorld::UniversalId::Type_Races); CSMWorld::UniversalId id (CSMWorld::UniversalId::Type_Races);
@ -64,7 +64,7 @@ int CSMTools::RaceCheckStage::setup()
return mRaces.getSize()+1; return mRaces.getSize()+1;
} }
void CSMTools::RaceCheckStage::perform (int stage, Messages& messages) void CSMTools::RaceCheckStage::perform (int stage, CSMDoc::Messages& messages)
{ {
if (stage==mRaces.getSize()) if (stage==mRaces.getSize())
performFinal (messages); performFinal (messages);

View file

@ -15,9 +15,9 @@ namespace CSMTools
const CSMWorld::IdCollection<ESM::Race>& mRaces; const CSMWorld::IdCollection<ESM::Race>& mRaces;
bool mPlayable; bool mPlayable;
void performPerRecord (int stage, Messages& messages); void performPerRecord (int stage, CSMDoc::Messages& messages);
void performFinal (Messages& messages); void performFinal (CSMDoc::Messages& messages);
public: public:
@ -26,7 +26,7 @@ namespace CSMTools
virtual int setup(); virtual int setup();
///< \return number of steps ///< \return number of steps
virtual void perform (int stage, Messages& messages); virtual void perform (int stage, CSMDoc::Messages& messages);
///< Messages resulting from this tage will be appended to \a messages. ///< Messages resulting from this tage will be appended to \a messages.
}; };
} }

View file

@ -18,7 +18,7 @@ CSMTools::ReferenceableCheckStage::ReferenceableCheckStage(
{ {
} }
void CSMTools::ReferenceableCheckStage::perform (int stage, Messages& messages) void CSMTools::ReferenceableCheckStage::perform (int stage, CSMDoc::Messages& messages)
{ {
//Checks for books, than, when stage is above mBooksSize goes to other checks, with (stage - PrevSum) as stage. //Checks for books, than, when stage is above mBooksSize goes to other checks, with (stage - PrevSum) as stage.
const int bookSize(mReferencables.getBooks().getSize()); const int bookSize(mReferencables.getBooks().getSize());
@ -232,7 +232,7 @@ int CSMTools::ReferenceableCheckStage::setup()
void CSMTools::ReferenceableCheckStage::bookCheck( void CSMTools::ReferenceableCheckStage::bookCheck(
int stage, int stage,
const CSMWorld::RefIdDataContainer< ESM::Book >& records, const CSMWorld::RefIdDataContainer< ESM::Book >& records,
Messages& messages) CSMDoc::Messages& messages)
{ {
const CSMWorld::RecordBase& baseRecord = records.getRecord(stage); const CSMWorld::RecordBase& baseRecord = records.getRecord(stage);
@ -250,7 +250,7 @@ void CSMTools::ReferenceableCheckStage::bookCheck(
void CSMTools::ReferenceableCheckStage::activatorCheck( void CSMTools::ReferenceableCheckStage::activatorCheck(
int stage, int stage,
const CSMWorld::RefIdDataContainer< ESM::Activator >& records, const CSMWorld::RefIdDataContainer< ESM::Activator >& records,
Messages& messages) CSMDoc::Messages& messages)
{ {
const CSMWorld::RecordBase& baseRecord = records.getRecord(stage); const CSMWorld::RecordBase& baseRecord = records.getRecord(stage);
@ -270,7 +270,7 @@ void CSMTools::ReferenceableCheckStage::activatorCheck(
void CSMTools::ReferenceableCheckStage::potionCheck( void CSMTools::ReferenceableCheckStage::potionCheck(
int stage, int stage,
const CSMWorld::RefIdDataContainer< ESM::Potion >& records, const CSMWorld::RefIdDataContainer< ESM::Potion >& records,
Messages& messages) CSMDoc::Messages& messages)
{ {
const CSMWorld::RecordBase& baseRecord = records.getRecord(stage); const CSMWorld::RecordBase& baseRecord = records.getRecord(stage);
@ -290,7 +290,7 @@ void CSMTools::ReferenceableCheckStage::potionCheck(
void CSMTools::ReferenceableCheckStage::apparatusCheck( void CSMTools::ReferenceableCheckStage::apparatusCheck(
int stage, int stage,
const CSMWorld::RefIdDataContainer< ESM::Apparatus >& records, const CSMWorld::RefIdDataContainer< ESM::Apparatus >& records,
Messages& messages) CSMDoc::Messages& messages)
{ {
const CSMWorld::RecordBase& baseRecord = records.getRecord(stage); const CSMWorld::RecordBase& baseRecord = records.getRecord(stage);
@ -310,7 +310,7 @@ void CSMTools::ReferenceableCheckStage::apparatusCheck(
void CSMTools::ReferenceableCheckStage::armorCheck( void CSMTools::ReferenceableCheckStage::armorCheck(
int stage, int stage,
const CSMWorld::RefIdDataContainer< ESM::Armor >& records, const CSMWorld::RefIdDataContainer< ESM::Armor >& records,
Messages& messages) CSMDoc::Messages& messages)
{ {
const CSMWorld::RecordBase& baseRecord = records.getRecord(stage); const CSMWorld::RecordBase& baseRecord = records.getRecord(stage);
@ -336,7 +336,7 @@ void CSMTools::ReferenceableCheckStage::armorCheck(
void CSMTools::ReferenceableCheckStage::clothingCheck( void CSMTools::ReferenceableCheckStage::clothingCheck(
int stage, int stage,
const CSMWorld::RefIdDataContainer< ESM::Clothing >& records, const CSMWorld::RefIdDataContainer< ESM::Clothing >& records,
Messages& messages) CSMDoc::Messages& messages)
{ {
const CSMWorld::RecordBase& baseRecord = records.getRecord(stage); const CSMWorld::RecordBase& baseRecord = records.getRecord(stage);
@ -353,7 +353,7 @@ void CSMTools::ReferenceableCheckStage::clothingCheck(
void CSMTools::ReferenceableCheckStage::containerCheck( void CSMTools::ReferenceableCheckStage::containerCheck(
int stage, int stage,
const CSMWorld::RefIdDataContainer< ESM::Container >& records, const CSMWorld::RefIdDataContainer< ESM::Container >& records,
Messages& messages) CSMDoc::Messages& messages)
{ {
const CSMWorld::RecordBase& baseRecord = records.getRecord(stage); const CSMWorld::RecordBase& baseRecord = records.getRecord(stage);
@ -381,7 +381,7 @@ void CSMTools::ReferenceableCheckStage::containerCheck(
void CSMTools::ReferenceableCheckStage::creatureCheck ( void CSMTools::ReferenceableCheckStage::creatureCheck (
int stage, const CSMWorld::RefIdDataContainer< ESM::Creature >& records, int stage, const CSMWorld::RefIdDataContainer< ESM::Creature >& records,
Messages& messages) CSMDoc::Messages& messages)
{ {
const CSMWorld::RecordBase& baseRecord = records.getRecord(stage); const CSMWorld::RecordBase& baseRecord = records.getRecord(stage);
@ -448,7 +448,7 @@ void CSMTools::ReferenceableCheckStage::creatureCheck (
void CSMTools::ReferenceableCheckStage::doorCheck( void CSMTools::ReferenceableCheckStage::doorCheck(
int stage, const CSMWorld::RefIdDataContainer< ESM::Door >& records, int stage, const CSMWorld::RefIdDataContainer< ESM::Door >& records,
Messages& messages) CSMDoc::Messages& messages)
{ {
const CSMWorld::RecordBase& baseRecord = records.getRecord(stage); const CSMWorld::RecordBase& baseRecord = records.getRecord(stage);
@ -469,7 +469,7 @@ void CSMTools::ReferenceableCheckStage::doorCheck(
void CSMTools::ReferenceableCheckStage::ingredientCheck( void CSMTools::ReferenceableCheckStage::ingredientCheck(
int stage, int stage,
const CSMWorld::RefIdDataContainer< ESM::Ingredient >& records, const CSMWorld::RefIdDataContainer< ESM::Ingredient >& records,
Messages& messages) CSMDoc::Messages& messages)
{ {
const CSMWorld::RecordBase& baseRecord = records.getRecord(stage); const CSMWorld::RecordBase& baseRecord = records.getRecord(stage);
@ -487,7 +487,7 @@ void CSMTools::ReferenceableCheckStage::ingredientCheck(
void CSMTools::ReferenceableCheckStage::creaturesLevListCheck( void CSMTools::ReferenceableCheckStage::creaturesLevListCheck(
int stage, int stage,
const CSMWorld::RefIdDataContainer< ESM::CreatureLevList >& records, const CSMWorld::RefIdDataContainer< ESM::CreatureLevList >& records,
Messages& messages) CSMDoc::Messages& messages)
{ {
const CSMWorld::RecordBase& baseRecord = records.getRecord(stage); const CSMWorld::RecordBase& baseRecord = records.getRecord(stage);
@ -505,7 +505,7 @@ void CSMTools::ReferenceableCheckStage::creaturesLevListCheck(
void CSMTools::ReferenceableCheckStage::itemLevelledListCheck( void CSMTools::ReferenceableCheckStage::itemLevelledListCheck(
int stage, int stage,
const CSMWorld::RefIdDataContainer< ESM::ItemLevList >& records, const CSMWorld::RefIdDataContainer< ESM::ItemLevList >& records,
Messages& messages) CSMDoc::Messages& messages)
{ {
const CSMWorld::RecordBase& baseRecord = records.getRecord(stage); const CSMWorld::RecordBase& baseRecord = records.getRecord(stage);
@ -522,7 +522,7 @@ void CSMTools::ReferenceableCheckStage::itemLevelledListCheck(
void CSMTools::ReferenceableCheckStage::lightCheck( void CSMTools::ReferenceableCheckStage::lightCheck(
int stage, const CSMWorld::RefIdDataContainer< ESM::Light >& records, int stage, const CSMWorld::RefIdDataContainer< ESM::Light >& records,
Messages& messages) CSMDoc::Messages& messages)
{ {
const CSMWorld::RecordBase& baseRecord = records.getRecord(stage); const CSMWorld::RecordBase& baseRecord = records.getRecord(stage);
@ -547,7 +547,7 @@ void CSMTools::ReferenceableCheckStage::lightCheck(
void CSMTools::ReferenceableCheckStage::lockpickCheck( void CSMTools::ReferenceableCheckStage::lockpickCheck(
int stage, int stage,
const CSMWorld::RefIdDataContainer< ESM::Lockpick >& records, const CSMWorld::RefIdDataContainer< ESM::Lockpick >& records,
Messages& messages) CSMDoc::Messages& messages)
{ {
const CSMWorld::RecordBase& baseRecord = records.getRecord(stage); const CSMWorld::RecordBase& baseRecord = records.getRecord(stage);
@ -567,7 +567,7 @@ void CSMTools::ReferenceableCheckStage::lockpickCheck(
void CSMTools::ReferenceableCheckStage::miscCheck( void CSMTools::ReferenceableCheckStage::miscCheck(
int stage, int stage,
const CSMWorld::RefIdDataContainer< ESM::Miscellaneous >& records, const CSMWorld::RefIdDataContainer< ESM::Miscellaneous >& records,
Messages& messages) CSMDoc::Messages& messages)
{ {
const CSMWorld::RecordBase& baseRecord = records.getRecord(stage); const CSMWorld::RecordBase& baseRecord = records.getRecord(stage);
@ -584,7 +584,7 @@ void CSMTools::ReferenceableCheckStage::miscCheck(
void CSMTools::ReferenceableCheckStage::npcCheck ( void CSMTools::ReferenceableCheckStage::npcCheck (
int stage, const CSMWorld::RefIdDataContainer< ESM::NPC >& records, int stage, const CSMWorld::RefIdDataContainer< ESM::NPC >& records,
Messages& messages) CSMDoc::Messages& messages)
{ {
const CSMWorld::RecordBase& baseRecord = records.getRecord(stage); const CSMWorld::RecordBase& baseRecord = records.getRecord(stage);
@ -701,7 +701,7 @@ void CSMTools::ReferenceableCheckStage::npcCheck (
void CSMTools::ReferenceableCheckStage::weaponCheck( void CSMTools::ReferenceableCheckStage::weaponCheck(
int stage, const CSMWorld::RefIdDataContainer< ESM::Weapon >& records, int stage, const CSMWorld::RefIdDataContainer< ESM::Weapon >& records,
Messages& messages) CSMDoc::Messages& messages)
{ {
const CSMWorld::RecordBase& baseRecord = records.getRecord (stage); const CSMWorld::RecordBase& baseRecord = records.getRecord (stage);
@ -778,7 +778,7 @@ void CSMTools::ReferenceableCheckStage::weaponCheck(
void CSMTools::ReferenceableCheckStage::probeCheck( void CSMTools::ReferenceableCheckStage::probeCheck(
int stage, int stage,
const CSMWorld::RefIdDataContainer< ESM::Probe >& records, const CSMWorld::RefIdDataContainer< ESM::Probe >& records,
Messages& messages) CSMDoc::Messages& messages)
{ {
const CSMWorld::RecordBase& baseRecord = records.getRecord(stage); const CSMWorld::RecordBase& baseRecord = records.getRecord(stage);
@ -796,7 +796,7 @@ void CSMTools::ReferenceableCheckStage::probeCheck(
void CSMTools::ReferenceableCheckStage::repairCheck ( void CSMTools::ReferenceableCheckStage::repairCheck (
int stage, const CSMWorld::RefIdDataContainer< ESM::Repair >& records, int stage, const CSMWorld::RefIdDataContainer< ESM::Repair >& records,
Messages& messages) CSMDoc::Messages& messages)
{ {
const CSMWorld::RecordBase& baseRecord = records.getRecord (stage); const CSMWorld::RecordBase& baseRecord = records.getRecord (stage);
@ -812,7 +812,7 @@ void CSMTools::ReferenceableCheckStage::repairCheck (
void CSMTools::ReferenceableCheckStage::staticCheck ( void CSMTools::ReferenceableCheckStage::staticCheck (
int stage, const CSMWorld::RefIdDataContainer< ESM::Static >& records, int stage, const CSMWorld::RefIdDataContainer< ESM::Static >& records,
Messages& messages) CSMDoc::Messages& messages)
{ {
const CSMWorld::RecordBase& baseRecord = records.getRecord (stage); const CSMWorld::RecordBase& baseRecord = records.getRecord (stage);
@ -828,7 +828,7 @@ void CSMTools::ReferenceableCheckStage::staticCheck (
//final check //final check
void CSMTools::ReferenceableCheckStage::finalCheck (Messages& messages) void CSMTools::ReferenceableCheckStage::finalCheck (CSMDoc::Messages& messages)
{ {
if (!mPlayerPresent) if (!mPlayerPresent)
messages.push_back (std::make_pair (CSMWorld::UniversalId::Type_Referenceables, messages.push_back (std::make_pair (CSMWorld::UniversalId::Type_Referenceables,
@ -839,7 +839,7 @@ void CSMTools::ReferenceableCheckStage::finalCheck (Messages& messages)
//Templates begins here //Templates begins here
template<typename Item> void CSMTools::ReferenceableCheckStage::inventoryItemCheck ( template<typename Item> void CSMTools::ReferenceableCheckStage::inventoryItemCheck (
const Item& someItem, Messages& messages, const std::string& someID, bool enchantable) const Item& someItem, CSMDoc::Messages& messages, const std::string& someID, bool enchantable)
{ {
if (someItem.mName.empty()) if (someItem.mName.empty())
messages.push_back (std::make_pair (someID, someItem.mId + " has an empty name")); messages.push_back (std::make_pair (someID, someItem.mId + " has an empty name"));
@ -865,7 +865,7 @@ template<typename Item> void CSMTools::ReferenceableCheckStage::inventoryItemChe
} }
template<typename Item> void CSMTools::ReferenceableCheckStage::inventoryItemCheck ( template<typename Item> void CSMTools::ReferenceableCheckStage::inventoryItemCheck (
const Item& someItem, Messages& messages, const std::string& someID) const Item& someItem, CSMDoc::Messages& messages, const std::string& someID)
{ {
if (someItem.mName.empty()) if (someItem.mName.empty())
messages.push_back (std::make_pair (someID, someItem.mId + " has an empty name")); messages.push_back (std::make_pair (someID, someItem.mId + " has an empty name"));
@ -888,7 +888,7 @@ template<typename Item> void CSMTools::ReferenceableCheckStage::inventoryItemChe
} }
template<typename Tool> void CSMTools::ReferenceableCheckStage::toolCheck ( template<typename Tool> void CSMTools::ReferenceableCheckStage::toolCheck (
const Tool& someTool, Messages& messages, const std::string& someID, bool canBeBroken) const Tool& someTool, CSMDoc::Messages& messages, const std::string& someID, bool canBeBroken)
{ {
if (someTool.mData.mQuality <= 0) if (someTool.mData.mQuality <= 0)
messages.push_back (std::make_pair (someID, someTool.mId + " has non-positive quality")); messages.push_back (std::make_pair (someID, someTool.mId + " has non-positive quality"));
@ -899,14 +899,14 @@ template<typename Tool> void CSMTools::ReferenceableCheckStage::toolCheck (
} }
template<typename Tool> void CSMTools::ReferenceableCheckStage::toolCheck ( template<typename Tool> void CSMTools::ReferenceableCheckStage::toolCheck (
const Tool& someTool, Messages& messages, const std::string& someID) const Tool& someTool, CSMDoc::Messages& messages, const std::string& someID)
{ {
if (someTool.mData.mQuality <= 0) if (someTool.mData.mQuality <= 0)
messages.push_back (std::make_pair (someID, someTool.mId + " has non-positive quality")); messages.push_back (std::make_pair (someID, someTool.mId + " has non-positive quality"));
} }
template<typename List> void CSMTools::ReferenceableCheckStage::listCheck ( template<typename List> void CSMTools::ReferenceableCheckStage::listCheck (
const List& someList, Messages& messages, const std::string& someID) const List& someList, CSMDoc::Messages& messages, const std::string& someID)
{ {
for (unsigned i = 0; i < someList.mList.size(); ++i) for (unsigned i = 0; i < someList.mList.size(); ++i)
{ {

View file

@ -17,56 +17,56 @@ namespace CSMTools
const CSMWorld::IdCollection<ESM::Class>& classes, const CSMWorld::IdCollection<ESM::Class>& classes,
const CSMWorld::IdCollection<ESM::Faction>& factions); const CSMWorld::IdCollection<ESM::Faction>& factions);
virtual void perform(int stage, Messages& messages); virtual void perform(int stage, CSMDoc::Messages& messages);
virtual int setup(); virtual int setup();
private: private:
//CONCRETE CHECKS //CONCRETE CHECKS
void bookCheck(int stage, const CSMWorld::RefIdDataContainer< ESM::Book >& records, Messages& messages); void bookCheck(int stage, const CSMWorld::RefIdDataContainer< ESM::Book >& records, CSMDoc::Messages& messages);
void activatorCheck(int stage, const CSMWorld::RefIdDataContainer< ESM::Activator >& records, Messages& messages); void activatorCheck(int stage, const CSMWorld::RefIdDataContainer< ESM::Activator >& records, CSMDoc::Messages& messages);
void potionCheck(int stage, const CSMWorld::RefIdDataContainer<ESM::Potion>& records, Messages& messages); void potionCheck(int stage, const CSMWorld::RefIdDataContainer<ESM::Potion>& records, CSMDoc::Messages& messages);
void apparatusCheck(int stage, const CSMWorld::RefIdDataContainer<ESM::Apparatus>& records, Messages& messages); void apparatusCheck(int stage, const CSMWorld::RefIdDataContainer<ESM::Apparatus>& records, CSMDoc::Messages& messages);
void armorCheck(int stage, const CSMWorld::RefIdDataContainer<ESM::Armor>& records, Messages& messages); void armorCheck(int stage, const CSMWorld::RefIdDataContainer<ESM::Armor>& records, CSMDoc::Messages& messages);
void clothingCheck(int stage, const CSMWorld::RefIdDataContainer<ESM::Clothing>& records, Messages& messages); void clothingCheck(int stage, const CSMWorld::RefIdDataContainer<ESM::Clothing>& records, CSMDoc::Messages& messages);
void containerCheck(int stage, const CSMWorld::RefIdDataContainer<ESM::Container>& records, Messages& messages); void containerCheck(int stage, const CSMWorld::RefIdDataContainer<ESM::Container>& records, CSMDoc::Messages& messages);
void creatureCheck(int stage, const CSMWorld::RefIdDataContainer<ESM::Creature>& records, Messages& messages); void creatureCheck(int stage, const CSMWorld::RefIdDataContainer<ESM::Creature>& records, CSMDoc::Messages& messages);
void doorCheck(int stage, const CSMWorld::RefIdDataContainer<ESM::Door>& records, Messages& messages); void doorCheck(int stage, const CSMWorld::RefIdDataContainer<ESM::Door>& records, CSMDoc::Messages& messages);
void ingredientCheck(int stage, const CSMWorld::RefIdDataContainer<ESM::Ingredient>& records, Messages& messages); void ingredientCheck(int stage, const CSMWorld::RefIdDataContainer<ESM::Ingredient>& records, CSMDoc::Messages& messages);
void creaturesLevListCheck(int stage, const CSMWorld::RefIdDataContainer<ESM::CreatureLevList>& records, Messages& messages); void creaturesLevListCheck(int stage, const CSMWorld::RefIdDataContainer<ESM::CreatureLevList>& records, CSMDoc::Messages& messages);
void itemLevelledListCheck(int stage, const CSMWorld::RefIdDataContainer<ESM::ItemLevList>& records, Messages& messages); void itemLevelledListCheck(int stage, const CSMWorld::RefIdDataContainer<ESM::ItemLevList>& records, CSMDoc::Messages& messages);
void lightCheck(int stage, const CSMWorld::RefIdDataContainer<ESM::Light>& records, Messages& messages); void lightCheck(int stage, const CSMWorld::RefIdDataContainer<ESM::Light>& records, CSMDoc::Messages& messages);
void lockpickCheck(int stage, const CSMWorld::RefIdDataContainer<ESM::Lockpick>& records, Messages& messages); void lockpickCheck(int stage, const CSMWorld::RefIdDataContainer<ESM::Lockpick>& records, CSMDoc::Messages& messages);
void miscCheck(int stage, const CSMWorld::RefIdDataContainer<ESM::Miscellaneous>& records, Messages& messages); void miscCheck(int stage, const CSMWorld::RefIdDataContainer<ESM::Miscellaneous>& records, CSMDoc::Messages& messages);
void npcCheck(int stage, const CSMWorld::RefIdDataContainer<ESM::NPC>& records, Messages& messages); void npcCheck(int stage, const CSMWorld::RefIdDataContainer<ESM::NPC>& records, CSMDoc::Messages& messages);
void weaponCheck(int stage, const CSMWorld::RefIdDataContainer<ESM::Weapon>& records, Messages& messages); void weaponCheck(int stage, const CSMWorld::RefIdDataContainer<ESM::Weapon>& records, CSMDoc::Messages& messages);
void probeCheck(int stage, const CSMWorld::RefIdDataContainer<ESM::Probe>& records, Messages& messages); void probeCheck(int stage, const CSMWorld::RefIdDataContainer<ESM::Probe>& records, CSMDoc::Messages& messages);
void repairCheck(int stage, const CSMWorld::RefIdDataContainer<ESM::Repair>& records, Messages& messages); void repairCheck(int stage, const CSMWorld::RefIdDataContainer<ESM::Repair>& records, CSMDoc::Messages& messages);
void staticCheck(int stage, const CSMWorld::RefIdDataContainer<ESM::Static>& records, Messages& messages); void staticCheck(int stage, const CSMWorld::RefIdDataContainer<ESM::Static>& records, CSMDoc::Messages& messages);
//FINAL CHECK //FINAL CHECK
void finalCheck (Messages& messages); void finalCheck (CSMDoc::Messages& messages);
//TEMPLATE CHECKS //TEMPLATE CHECKS
template<typename ITEM> void inventoryItemCheck(const ITEM& someItem, template<typename ITEM> void inventoryItemCheck(const ITEM& someItem,
Messages& messages, CSMDoc::Messages& messages,
const std::string& someID, const std::string& someID,
bool enchantable); //for all enchantable items. bool enchantable); //for all enchantable items.
template<typename ITEM> void inventoryItemCheck(const ITEM& someItem, template<typename ITEM> void inventoryItemCheck(const ITEM& someItem,
Messages& messages, CSMDoc::Messages& messages,
const std::string& someID); //for non-enchantable items. const std::string& someID); //for non-enchantable items.
template<typename TOOL> void toolCheck(const TOOL& someTool, template<typename TOOL> void toolCheck(const TOOL& someTool,
Messages& messages, CSMDoc::Messages& messages,
const std::string& someID, const std::string& someID,
bool canbebroken); //for tools with uses. bool canbebroken); //for tools with uses.
template<typename TOOL> void toolCheck(const TOOL& someTool, template<typename TOOL> void toolCheck(const TOOL& someTool,
Messages& messages, CSMDoc::Messages& messages,
const std::string& someID); //for tools without uses. const std::string& someID); //for tools without uses.
template<typename LIST> void listCheck(const LIST& someList, template<typename LIST> void listCheck(const LIST& someList,
Messages& messages, CSMDoc::Messages& messages,
const std::string& someID); const std::string& someID);
const CSMWorld::RefIdData& mReferencables; const CSMWorld::RefIdData& mReferencables;

View file

@ -17,7 +17,7 @@ int CSMTools::RegionCheckStage::setup()
return mRegions.getSize(); return mRegions.getSize();
} }
void CSMTools::RegionCheckStage::perform (int stage, Messages& messages) void CSMTools::RegionCheckStage::perform (int stage, CSMDoc::Messages& messages)
{ {
const CSMWorld::Record<ESM::Region>& record = mRegions.getRecord (stage); const CSMWorld::Record<ESM::Region>& record = mRegions.getRecord (stage);

View file

@ -21,7 +21,7 @@ namespace CSMTools
virtual int setup(); virtual int setup();
///< \return number of steps ///< \return number of steps
virtual void perform (int stage, Messages& messages); virtual void perform (int stage, CSMDoc::Messages& messages);
///< Messages resulting from this tage will be appended to \a messages. ///< Messages resulting from this tage will be appended to \a messages.
}; };
} }

View file

@ -16,7 +16,7 @@ int CSMTools::ReportModel::columnCount (const QModelIndex & parent) const
if (parent.isValid()) if (parent.isValid())
return 0; return 0;
return 2; return 3;
} }
QVariant CSMTools::ReportModel::data (const QModelIndex & index, int role) const QVariant CSMTools::ReportModel::data (const QModelIndex & index, int role) const
@ -26,8 +26,11 @@ QVariant CSMTools::ReportModel::data (const QModelIndex & index, int role) const
if (index.column()==0) if (index.column()==0)
return static_cast<int> (mRows.at (index.row()).first.getType()); return static_cast<int> (mRows.at (index.row()).first.getType());
else
return mRows.at (index.row()).second.c_str(); if (index.column()==1)
return QString::fromUtf8 (mRows.at (index.row()).second.first.c_str());
return QString::fromUtf8 (mRows.at (index.row()).second.second.c_str());
} }
QVariant CSMTools::ReportModel::headerData (int section, Qt::Orientation orientation, int role) const QVariant CSMTools::ReportModel::headerData (int section, Qt::Orientation orientation, int role) const
@ -38,7 +41,13 @@ QVariant CSMTools::ReportModel::headerData (int section, Qt::Orientation orienta
if (orientation==Qt::Vertical) if (orientation==Qt::Vertical)
return QVariant(); return QVariant();
return tr (section==0 ? "Type" : "Description"); if (section==0)
return "Type";
if (section==1)
return "Description";
return "Hint";
} }
bool CSMTools::ReportModel::removeRows (int row, int count, const QModelIndex& parent) bool CSMTools::ReportModel::removeRows (int row, int count, const QModelIndex& parent)
@ -51,11 +60,12 @@ bool CSMTools::ReportModel::removeRows (int row, int count, const QModelIndex& p
return true; return true;
} }
void CSMTools::ReportModel::add (const CSMWorld::UniversalId& id, const std::string& message) void CSMTools::ReportModel::add (const CSMWorld::UniversalId& id, const std::string& message,
const std::string& hint)
{ {
beginInsertRows (QModelIndex(), mRows.size(), mRows.size()); beginInsertRows (QModelIndex(), mRows.size(), mRows.size());
mRows.push_back (std::make_pair (id, message)); mRows.push_back (std::make_pair (id, std::make_pair (message, hint)));
endInsertRows(); endInsertRows();
} }
@ -64,3 +74,8 @@ const CSMWorld::UniversalId& CSMTools::ReportModel::getUniversalId (int row) con
{ {
return mRows.at (row).first; return mRows.at (row).first;
} }
std::string CSMTools::ReportModel::getHint (int row) const
{
return mRows.at (row).second.second;
}

View file

@ -14,7 +14,7 @@ namespace CSMTools
{ {
Q_OBJECT Q_OBJECT
std::vector<std::pair<CSMWorld::UniversalId, std::string> > mRows; std::vector<std::pair<CSMWorld::UniversalId, std::pair<std::string, std::string> > > mRows;
public: public:
@ -28,9 +28,12 @@ namespace CSMTools
virtual bool removeRows (int row, int count, const QModelIndex& parent = QModelIndex()); virtual bool removeRows (int row, int count, const QModelIndex& parent = QModelIndex());
void add (const CSMWorld::UniversalId& id, const std::string& message); void add (const CSMWorld::UniversalId& id, const std::string& message,
const std::string& hint = "");
const CSMWorld::UniversalId& getUniversalId (int row) const; const CSMWorld::UniversalId& getUniversalId (int row) const;
std::string getHint (int row) const;
}; };
} }

View file

@ -28,7 +28,11 @@ void CSMTools::ScriptCheckStage::report (const std::string& message, const Compi
<< ", line " << loc.mLine << ", column " << loc.mColumn << ", line " << loc.mLine << ", column " << loc.mColumn
<< " (" << loc.mLiteral << "): " << message; << " (" << loc.mLiteral << "): " << message;
mMessages->push_back (std::make_pair (id, stream.str())); std::ostringstream hintStream;
hintStream << "l:" << loc.mLine << " " << loc.mColumn;
mMessages->add (id, stream.str(), hintStream.str());
} }
void CSMTools::ScriptCheckStage::report (const std::string& message, Type type) void CSMTools::ScriptCheckStage::report (const std::string& message, Type type)
@ -58,7 +62,7 @@ int CSMTools::ScriptCheckStage::setup()
return mDocument.getData().getScripts().getSize(); return mDocument.getData().getScripts().getSize();
} }
void CSMTools::ScriptCheckStage::perform (int stage, Messages& messages) void CSMTools::ScriptCheckStage::perform (int stage, CSMDoc::Messages& messages)
{ {
mId = mDocument.getData().getScripts().getId (stage); mId = mDocument.getData().getScripts().getId (stage);

View file

@ -23,7 +23,7 @@ namespace CSMTools
CSMWorld::ScriptContext mContext; CSMWorld::ScriptContext mContext;
std::string mId; std::string mId;
std::string mFile; std::string mFile;
Messages *mMessages; CSMDoc::Messages *mMessages;
virtual void report (const std::string& message, const Compiler::TokenLoc& loc, Type type); virtual void report (const std::string& message, const Compiler::TokenLoc& loc, Type type);
///< Report error to the user. ///< Report error to the user.
@ -38,7 +38,7 @@ namespace CSMTools
virtual int setup(); virtual int setup();
///< \return number of steps ///< \return number of steps
virtual void perform (int stage, Messages& messages); virtual void perform (int stage, CSMDoc::Messages& messages);
///< Messages resulting from this tage will be appended to \a messages. ///< Messages resulting from this tage will be appended to \a messages.
}; };
} }

View file

@ -16,7 +16,7 @@ int CSMTools::SkillCheckStage::setup()
return mSkills.getSize(); return mSkills.getSize();
} }
void CSMTools::SkillCheckStage::perform (int stage, Messages& messages) void CSMTools::SkillCheckStage::perform (int stage, CSMDoc::Messages& messages)
{ {
const CSMWorld::Record<ESM::Skill>& record = mSkills.getRecord (stage); const CSMWorld::Record<ESM::Skill>& record = mSkills.getRecord (stage);

View file

@ -21,7 +21,7 @@ namespace CSMTools
virtual int setup(); virtual int setup();
///< \return number of steps ///< \return number of steps
virtual void perform (int stage, Messages& messages); virtual void perform (int stage, CSMDoc::Messages& messages);
///< Messages resulting from this tage will be appended to \a messages. ///< Messages resulting from this tage will be appended to \a messages.
}; };
} }

View file

@ -16,7 +16,7 @@ int CSMTools::SoundCheckStage::setup()
return mSounds.getSize(); return mSounds.getSize();
} }
void CSMTools::SoundCheckStage::perform (int stage, Messages& messages) void CSMTools::SoundCheckStage::perform (int stage, CSMDoc::Messages& messages)
{ {
const CSMWorld::Record<ESM::Sound>& record = mSounds.getRecord (stage); const CSMWorld::Record<ESM::Sound>& record = mSounds.getRecord (stage);

View file

@ -21,7 +21,7 @@ namespace CSMTools
virtual int setup(); virtual int setup();
///< \return number of steps ///< \return number of steps
virtual void perform (int stage, Messages& messages); virtual void perform (int stage, CSMDoc::Messages& messages);
///< Messages resulting from this tage will be appended to \a messages. ///< Messages resulting from this tage will be appended to \a messages.
}; };
} }

View file

@ -17,7 +17,7 @@ int CSMTools::SpellCheckStage::setup()
return mSpells.getSize(); return mSpells.getSize();
} }
void CSMTools::SpellCheckStage::perform (int stage, Messages& messages) void CSMTools::SpellCheckStage::perform (int stage, CSMDoc::Messages& messages)
{ {
const CSMWorld::Record<ESM::Spell>& record = mSpells.getRecord (stage); const CSMWorld::Record<ESM::Spell>& record = mSpells.getRecord (stage);

View file

@ -21,7 +21,7 @@ namespace CSMTools
virtual int setup(); virtual int setup();
///< \return number of steps ///< \return number of steps
virtual void perform (int stage, Messages& messages); virtual void perform (int stage, CSMDoc::Messages& messages);
///< Messages resulting from this tage will be appended to \a messages. ///< Messages resulting from this tage will be appended to \a messages.
}; };
} }

View file

@ -48,8 +48,8 @@ CSMDoc::Operation *CSMTools::Tools::getVerifier()
connect (mVerifier, SIGNAL (progress (int, int, int)), this, SIGNAL (progress (int, int, int))); connect (mVerifier, SIGNAL (progress (int, int, int)), this, SIGNAL (progress (int, int, int)));
connect (mVerifier, SIGNAL (done (int, bool)), this, SIGNAL (done (int, bool))); connect (mVerifier, SIGNAL (done (int, bool)), this, SIGNAL (done (int, bool)));
connect (mVerifier, connect (mVerifier,
SIGNAL (reportMessage (const CSMWorld::UniversalId&, const std::string&, int)), SIGNAL (reportMessage (const CSMWorld::UniversalId&, const std::string&, const std::string&, int)),
this, SLOT (verifierMessage (const CSMWorld::UniversalId&, const std::string&, int))); this, SLOT (verifierMessage (const CSMWorld::UniversalId&, const std::string&, const std::string&, int)));
std::vector<std::string> mandatoryIds; // I want C++11, damn it! std::vector<std::string> mandatoryIds; // I want C++11, damn it!
mandatoryIds.push_back ("Day"); mandatoryIds.push_back ("Day");
@ -155,11 +155,11 @@ CSMTools::ReportModel *CSMTools::Tools::getReport (const CSMWorld::UniversalId&
} }
void CSMTools::Tools::verifierMessage (const CSMWorld::UniversalId& id, const std::string& message, void CSMTools::Tools::verifierMessage (const CSMWorld::UniversalId& id, const std::string& message,
int type) const std::string& hint, int type)
{ {
std::map<int, int>::iterator iter = mActiveReports.find (type); std::map<int, int>::iterator iter = mActiveReports.find (type);
if (iter!=mActiveReports.end()) if (iter!=mActiveReports.end())
mReports[iter->second]->add (id, message); mReports[iter->second]->add (id, message, hint);
} }

View file

@ -64,7 +64,7 @@ namespace CSMTools
private slots: private slots:
void verifierMessage (const CSMWorld::UniversalId& id, const std::string& message, void verifierMessage (const CSMWorld::UniversalId& id, const std::string& message,
int type); const std::string& hint, int type);
signals: signals:

View file

@ -272,7 +272,7 @@ namespace CSMWorld
{ {
ESXRecordT record2 = record.get(); ESXRecordT record2 = record.get();
record2.mData.mUseValue[mIndex] = data.toInt(); record2.mData.mUseValue[mIndex] = data.toFloat();
record.setModified (record2); record.setModified (record2);
} }

View file

@ -60,7 +60,7 @@ int CSMWorld::Data::count (RecordBase::State state, const CollectionBase& collec
CSMWorld::Data::Data (ToUTF8::FromType encoding, const ResourcesManager& resourcesManager) CSMWorld::Data::Data (ToUTF8::FromType encoding, const ResourcesManager& resourcesManager)
: mEncoder (encoding), mPathgrids (mCells), mRefs (mCells), : mEncoder (encoding), mPathgrids (mCells), mRefs (mCells),
mResourcesManager (resourcesManager), mReader (0), mDialogue (0) mResourcesManager (resourcesManager), mReader (0), mDialogue (0), mReaderIndex(0)
{ {
mGlobals.addColumn (new StringIdColumn<ESM::Global>); mGlobals.addColumn (new StringIdColumn<ESM::Global>);
mGlobals.addColumn (new RecordStateColumn<ESM::Global>); mGlobals.addColumn (new RecordStateColumn<ESM::Global>);
@ -659,6 +659,7 @@ int CSMWorld::Data::startLoading (const boost::filesystem::path& path, bool base
mReader = new ESM::ESMReader; mReader = new ESM::ESMReader;
mReader->setEncoder (&mEncoder); mReader->setEncoder (&mEncoder);
mReader->setIndex(mReaderIndex++);
mReader->open (path.string()); mReader->open (path.string());
mBase = base; mBase = base;
@ -670,16 +671,24 @@ int CSMWorld::Data::startLoading (const boost::filesystem::path& path, bool base
return mReader->getRecordCount(); return mReader->getRecordCount();
} }
bool CSMWorld::Data::continueLoading (CSMDoc::Stage::Messages& messages) bool CSMWorld::Data::continueLoading (CSMDoc::Messages& messages)
{ {
if (!mReader) if (!mReader)
throw std::logic_error ("can't continue loading, because no load has been started"); throw std::logic_error ("can't continue loading, because no load has been started");
if (!mReader->hasMoreRecs()) if (!mReader->hasMoreRecs())
{ {
// Don't delete the Reader yet. Some record types store a reference to the Reader to handle on-demand loading if (mBase)
{
// Don't delete the Reader yet. Some record types store a reference to the Reader to handle on-demand loading.
// We don't store non-base reader, because everything going into modified will be
// fully loaded during the initial loading process.
boost::shared_ptr<ESM::ESMReader> ptr(mReader); boost::shared_ptr<ESM::ESMReader> ptr(mReader);
mReaders.push_back(ptr); mReaders.push_back(ptr);
}
else
delete mReader;
mReader = 0; mReader = 0;
mDialogue = 0; mDialogue = 0;
@ -712,7 +721,18 @@ bool CSMWorld::Data::continueLoading (CSMDoc::Stage::Messages& messages)
case ESM::REC_PGRD: mPathgrids.load (*mReader, mBase); break; case ESM::REC_PGRD: mPathgrids.load (*mReader, mBase); break;
case ESM::REC_LTEX: mLandTextures.load (*mReader, mBase); break; case ESM::REC_LTEX: mLandTextures.load (*mReader, mBase); break;
case ESM::REC_LAND: mLand.load(*mReader, mBase); break;
case ESM::REC_LAND:
{
int index = mLand.load(*mReader, mBase);
if (index!=-1 && !mBase)
mLand.getRecord (index).mModified.mLand->loadData (
ESM::Land::DATA_VHGT | ESM::Land::DATA_VNML | ESM::Land::DATA_VCLR |
ESM::Land::DATA_VTEX);
break;
}
case ESM::REC_CELL: case ESM::REC_CELL:
{ {
@ -774,8 +794,8 @@ bool CSMWorld::Data::continueLoading (CSMDoc::Stage::Messages& messages)
} }
else else
{ {
messages.push_back (std::make_pair (UniversalId::Type_None, messages.add (UniversalId::Type_None,
"Trying to delete dialogue record " + id + " which does not exist")); "Trying to delete dialogue record " + id + " which does not exist");
} }
} }
else else
@ -791,8 +811,8 @@ bool CSMWorld::Data::continueLoading (CSMDoc::Stage::Messages& messages)
{ {
if (!mDialogue) if (!mDialogue)
{ {
messages.push_back (std::make_pair (UniversalId::Type_None, messages.add (UniversalId::Type_None,
"Found info record not following a dialogue record")); "Found info record not following a dialogue record");
mReader->skipRecord(); mReader->skipRecord();
break; break;
@ -835,8 +855,7 @@ bool CSMWorld::Data::continueLoading (CSMDoc::Stage::Messages& messages)
if (unhandledRecord) if (unhandledRecord)
{ {
messages.push_back (std::make_pair (UniversalId::Type_None, messages.add (UniversalId::Type_None, "Unsupported record type: " + n.toString());
"Unsupported record type: " + n.toString()));
mReader->skipRecord(); mReader->skipRecord();
} }

View file

@ -98,6 +98,7 @@ namespace CSMWorld
bool mBase; bool mBase;
bool mProject; bool mProject;
std::map<std::string, std::map<ESM::RefNum, std::string> > mRefLoadCache; std::map<std::string, std::map<ESM::RefNum, std::string> > mRefLoadCache;
int mReaderIndex;
std::vector<boost::shared_ptr<ESM::ESMReader> > mReaders; std::vector<boost::shared_ptr<ESM::ESMReader> > mReaders;
@ -243,7 +244,7 @@ namespace CSMWorld
/// ///
///< \return estimated number of records ///< \return estimated number of records
bool continueLoading (CSMDoc::Stage::Messages& messages); bool continueLoading (CSMDoc::Messages& messages);
///< \return Finished? ///< \return Finished?
bool hasId (const std::string& id) const; bool hasId (const std::string& id) const;

View file

@ -15,12 +15,15 @@ namespace CSMWorld
public: public:
void load (ESM::ESMReader& reader, bool base); /// \return Index of loaded record (-1 if no record was loaded)
int load (ESM::ESMReader& reader, bool base);
/// \param index Index at which the record can be found. /// \param index Index at which the record can be found.
/// Special values: -2 index unknown, -1 record does not exist yet and therefore /// Special values: -2 index unknown, -1 record does not exist yet and therefore
/// does not have an index /// does not have an index
void load (const ESXRecordT& record, bool base, int index = -2); ///
/// \return index
int load (const ESXRecordT& record, bool base, int index = -2);
bool tryDelete (const std::string& id); 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. ///< Try deleting \a id. If the id does not exist or can't be deleted the call is ignored.
@ -36,7 +39,7 @@ namespace CSMWorld
} }
template<typename ESXRecordT, typename IdAccessorT> template<typename ESXRecordT, typename IdAccessorT>
void IdCollection<ESXRecordT, IdAccessorT>::load (ESM::ESMReader& reader, bool base) int IdCollection<ESXRecordT, IdAccessorT>::load (ESM::ESMReader& reader, bool base)
{ {
std::string id = reader.getHNOString ("NAME"); std::string id = reader.getHNOString ("NAME");
@ -64,6 +67,8 @@ namespace CSMWorld
record.mState = RecordBase::State_Deleted; record.mState = RecordBase::State_Deleted;
this->setRecord (index, record); this->setRecord (index, record);
} }
return -1;
} }
else else
{ {
@ -88,12 +93,12 @@ namespace CSMWorld
index = newIndex; index = newIndex;
} }
load (record, base, index); return load (record, base, index);
} }
} }
template<typename ESXRecordT, typename IdAccessorT> template<typename ESXRecordT, typename IdAccessorT>
void IdCollection<ESXRecordT, IdAccessorT>::load (const ESXRecordT& record, bool base, int IdCollection<ESXRecordT, IdAccessorT>::load (const ESXRecordT& record, bool base,
int index) int index)
{ {
if (index==-2) if (index==-2)
@ -106,6 +111,7 @@ namespace CSMWorld
record2.mState = base ? RecordBase::State_BaseOnly : RecordBase::State_ModifiedOnly; record2.mState = base ? RecordBase::State_BaseOnly : RecordBase::State_ModifiedOnly;
(base ? record2.mBase : record2.mModified) = record; (base ? record2.mBase : record2.mModified) = record;
index = this->getSize();
this->appendRecord (record2); this->appendRecord (record2);
} }
else else
@ -120,6 +126,8 @@ namespace CSMWorld
this->setRecord (index, record2); this->setRecord (index, record2);
} }
return index;
} }
template<typename ESXRecordT, typename IdAccessorT> template<typename ESXRecordT, typename IdAccessorT>

View file

@ -11,7 +11,7 @@
#include "record.hpp" #include "record.hpp"
void CSMWorld::RefCollection::load (ESM::ESMReader& reader, int cellIndex, bool base, void CSMWorld::RefCollection::load (ESM::ESMReader& reader, int cellIndex, bool base,
std::map<ESM::RefNum, std::string>& cache, CSMDoc::Stage::Messages& messages) std::map<ESM::RefNum, std::string>& cache, CSMDoc::Messages& messages)
{ {
Record<Cell> cell = mCells.getRecord (cellIndex); Record<Cell> cell = mCells.getRecord (cellIndex);
@ -36,8 +36,7 @@ void CSMWorld::RefCollection::load (ESM::ESMReader& reader, int cellIndex, bool
CSMWorld::UniversalId id (CSMWorld::UniversalId::Type_Cell, CSMWorld::UniversalId id (CSMWorld::UniversalId::Type_Cell,
mCells.getId (cellIndex)); mCells.getId (cellIndex));
messages.push_back (std::make_pair (id, messages.add (id, "Attempt to delete a non-existing reference");
"Attempt to delete a non-existing reference"));
continue; continue;
} }

View file

@ -28,7 +28,7 @@ namespace CSMWorld
void load (ESM::ESMReader& reader, int cellIndex, bool base, void load (ESM::ESMReader& reader, int cellIndex, bool base,
std::map<ESM::RefNum, std::string>& cache, std::map<ESM::RefNum, std::string>& cache,
CSMDoc::Stage::Messages& messages); CSMDoc::Messages& messages);
///< Load a sequence of references. ///< Load a sequence of references.
std::string getNewId(); std::string getNewId();

View file

@ -3,6 +3,7 @@
#include <sstream> #include <sstream>
#include <stdexcept> #include <stdexcept>
#include <algorithm>
#include <OgreResourceGroupManager.h> #include <OgreResourceGroupManager.h>
@ -55,7 +56,9 @@ CSMWorld::Resources::Resources (const std::string& baseDirectory, UniversalId::T
std::string file = iter->substr (baseSize+1); std::string file = iter->substr (baseSize+1);
mFiles.push_back (file); mFiles.push_back (file);
mIndex.insert (std::make_pair (file, static_cast<int> (mFiles.size())-1)); std::replace (file.begin(), file.end(), '\\', '/');
mIndex.insert (std::make_pair (
Misc::StringUtils::lowerCase (file), static_cast<int> (mFiles.size())-1));
} }
} }
} }
@ -89,6 +92,8 @@ int CSMWorld::Resources::searchId (const std::string& id) const
{ {
std::string id2 = Misc::StringUtils::lowerCase (id); std::string id2 = Misc::StringUtils::lowerCase (id);
std::replace (id2.begin(), id2.end(), '\\', '/');
std::map<std::string, int>::const_iterator iter = mIndex.find (id2); std::map<std::string, int>::const_iterator iter = mIndex.find (id2);
if (iter==mIndex.end()) if (iter==mIndex.end())

View file

@ -328,7 +328,7 @@ std::string CSMWorld::UniversalId::getIcon() const
for (int i=0; typeData[i].mName; ++i) for (int i=0; typeData[i].mName; ++i)
if (typeData[i].mType==mType) if (typeData[i].mType==mType)
return typeData[i].mIcon ? typeData[i].mIcon : ""; return typeData[i].mIcon ? typeData[i].mIcon : ":placeholder";
throw std::logic_error ("failed to retrieve UniversalId type icon"); throw std::logic_error ("failed to retrieve UniversalId type icon");
} }

View file

@ -16,7 +16,6 @@
#include "../../model/world/idtable.hpp" #include "../../model/world/idtable.hpp"
#include "../world/subviews.hpp" #include "../world/subviews.hpp"
#include "../world/physicsmanager.hpp"
#include "../tools/subviews.hpp" #include "../tools/subviews.hpp"
@ -407,8 +406,6 @@ CSVDoc::View::View (ViewManager& viewManager, CSMDoc::Document *document, int to
mSubViewFactory.add (CSMWorld::UniversalId::Type_RunLog, new SubViewFactory<RunLogSubView>); mSubViewFactory.add (CSMWorld::UniversalId::Type_RunLog, new SubViewFactory<RunLogSubView>);
connect (mOperations, SIGNAL (abortOperation (int)), this, SLOT (abortOperation (int))); connect (mOperations, SIGNAL (abortOperation (int)), this, SLOT (abortOperation (int)));
CSVWorld::PhysicsManager::instance()->setupPhysics(document);
} }
CSVDoc::View::~View() CSVDoc::View::~View()
@ -464,8 +461,7 @@ void CSVDoc::View::addSubView (const CSMWorld::UniversalId& id, const std::strin
{ {
CSMSettings::UserSettings &userSettings = CSMSettings::UserSettings::instance(); CSMSettings::UserSettings &userSettings = CSMSettings::UserSettings::instance();
const std::vector<CSMWorld::UniversalId::Type> referenceables(CSMWorld::UniversalId::listReferenceableTypes()); bool isReferenceable = id.getClass() == CSMWorld::UniversalId::Class_RefRecord;
bool isReferenceable = std::find(referenceables.begin(), referenceables.end(), id.getType()) != referenceables.end();
// User setting to reuse sub views (on a per top level view basis) // User setting to reuse sub views (on a per top level view basis)
bool reuse = bool reuse =
@ -474,10 +470,14 @@ void CSVDoc::View::addSubView (const CSMWorld::UniversalId& id, const std::strin
{ {
foreach(SubView *sb, mSubViews) foreach(SubView *sb, mSubViews)
{ {
if((isReferenceable && (CSMWorld::UniversalId(CSMWorld::UniversalId::Type_Referenceable, id.getId()) == CSMWorld::UniversalId(CSMWorld::UniversalId::Type_Referenceable, sb->getUniversalId().getId()))) bool isSubViewReferenceable =
|| (!isReferenceable && (id == sb->getUniversalId()))) sb->getUniversalId().getType() == CSMWorld::UniversalId::Type_Referenceable;
if((isReferenceable && isSubViewReferenceable && id.getId() == sb->getUniversalId().getId())
||
(!isReferenceable && id == sb->getUniversalId()))
{ {
sb->setFocus(Qt::OtherFocusReason); // FIXME: focus not quite working sb->setFocus();
return; return;
} }
} }
@ -497,7 +497,7 @@ void CSVDoc::View::addSubView (const CSMWorld::UniversalId& id, const std::strin
} }
SubView *view = NULL; SubView *view = NULL;
if(std::find(referenceables.begin(), referenceables.end(), id.getType()) != referenceables.end()) if(isReferenceable)
{ {
view = mSubViewFactory.makeSubView (CSMWorld::UniversalId(CSMWorld::UniversalId::Type_Referenceable, id.getId()), *mDocument); view = mSubViewFactory.makeSubView (CSMWorld::UniversalId(CSMWorld::UniversalId::Type_Referenceable, id.getId()), *mDocument);
} }

View file

@ -16,7 +16,6 @@
#include "../world/vartypedelegate.hpp" #include "../world/vartypedelegate.hpp"
#include "../world/recordstatusdelegate.hpp" #include "../world/recordstatusdelegate.hpp"
#include "../world/idtypedelegate.hpp" #include "../world/idtypedelegate.hpp"
#include "../world/physicsmanager.hpp"
#include "../../model/settings/usersettings.hpp" #include "../../model/settings/usersettings.hpp"
@ -219,7 +218,6 @@ void CSVDoc::ViewManager::removeDocAndView (CSMDoc::Document *document)
mDocumentManager.removeDocument(document); mDocumentManager.removeDocument(document);
(*iter)->deleteLater(); (*iter)->deleteLater();
mViews.erase (iter); mViews.erase (iter);
CSVWorld::PhysicsManager::instance()->removeDocument(document);
updateIndices(); updateIndices();
return; return;

View file

@ -60,7 +60,7 @@ bool CSVRender::Cell::addObjects (int start, int end)
} }
CSVRender::Cell::Cell (CSMWorld::Data& data, Ogre::SceneManager *sceneManager, CSVRender::Cell::Cell (CSMWorld::Data& data, Ogre::SceneManager *sceneManager,
const std::string& id, CSVWorld::PhysicsSystem *physics, const Ogre::Vector3& origin) const std::string& id, boost::shared_ptr<CSVWorld::PhysicsSystem> physics, const Ogre::Vector3& origin)
: mData (data), mId (Misc::StringUtils::lowerCase (id)), mSceneMgr(sceneManager), mPhysics(physics) : mData (data), mId (Misc::StringUtils::lowerCase (id)), mSceneMgr(sceneManager), mPhysics(physics)
{ {
mCellNode = sceneManager->getRootSceneNode()->createChildSceneNode(); mCellNode = sceneManager->getRootSceneNode()->createChildSceneNode();

View file

@ -3,6 +3,9 @@
#include <string> #include <string>
#include <map> #include <map>
#include <memory>
#include <boost/shared_ptr.hpp>
#include <OgreVector3.h> #include <OgreVector3.h>
@ -37,7 +40,7 @@ namespace CSVRender
Ogre::SceneNode *mCellNode; Ogre::SceneNode *mCellNode;
std::map<std::string, Object *> mObjects; std::map<std::string, Object *> mObjects;
std::auto_ptr<Terrain::TerrainGrid> mTerrain; std::auto_ptr<Terrain::TerrainGrid> mTerrain;
CSVWorld::PhysicsSystem *mPhysics; boost::shared_ptr<CSVWorld::PhysicsSystem> mPhysics;
Ogre::SceneManager *mSceneMgr; Ogre::SceneManager *mSceneMgr;
int mX; int mX;
int mY; int mY;
@ -55,7 +58,7 @@ namespace CSVRender
public: public:
Cell (CSMWorld::Data& data, Ogre::SceneManager *sceneManager, const std::string& id, Cell (CSMWorld::Data& data, Ogre::SceneManager *sceneManager, const std::string& id,
CSVWorld::PhysicsSystem *physics, const Ogre::Vector3& origin = Ogre::Vector3 (0, 0, 0)); boost::shared_ptr<CSVWorld::PhysicsSystem> physics, const Ogre::Vector3& origin = Ogre::Vector3 (0, 0, 0));
~Cell(); ~Cell();

View file

@ -0,0 +1,19 @@
#include "editmode.hpp"
#include "worldspacewidget.hpp"
CSVRender::EditMode::EditMode (WorldspaceWidget *worldspaceWidget, const QIcon& icon,
unsigned int mask, const QString& tooltip, QWidget *parent)
: ModeButton (icon, tooltip, parent), mWorldspaceWidget (worldspaceWidget), mMask (mask)
{}
unsigned int CSVRender::EditMode::getInteractionMask() const
{
return mMask;
}
void CSVRender::EditMode::activate (CSVWidget::SceneToolbar *toolbar)
{
mWorldspaceWidget->setInteractionMask (mMask);
}

View file

@ -0,0 +1,28 @@
#ifndef CSV_RENDER_EDITMODE_H
#define CSV_RENDER_EDITMODE_H
#include "../widget/modebutton.hpp"
namespace CSVRender
{
class WorldspaceWidget;
class EditMode : public CSVWidget::ModeButton
{
Q_OBJECT
WorldspaceWidget *mWorldspaceWidget;
unsigned int mMask;
public:
EditMode (WorldspaceWidget *worldspaceWidget, const QIcon& icon, unsigned int mask,
const QString& tooltip = "", QWidget *parent = 0);
unsigned int getInteractionMask() const;
virtual void activate (CSVWidget::SceneToolbar *toolbar);
};
}
#endif

View file

@ -8,10 +8,10 @@ namespace CSVRender
{ {
// elements that are part of the actual scene // elements that are part of the actual scene
Element_Reference = 0x1, Element_Reference = 0x1,
Element_Terrain = 0x2, Element_Pathgrid = 0x2,
Element_Water = 0x4, Element_Water = 0x4,
Element_Pathgrid = 0x8, Element_Fog = 0x8,
Element_Fog = 0x10, Element_Terrain = 0x10,
// control elements // control elements
Element_CellMarker = 0x10000, Element_CellMarker = 0x10000,

View file

@ -56,7 +56,7 @@ namespace CSVRender
// //
MouseState::MouseState(WorldspaceWidget *parent) MouseState::MouseState(WorldspaceWidget *parent)
: mParent(parent), mPhysics(parent->getPhysics()), mSceneManager(parent->getSceneManager()) : mParent(parent), mPhysics(parent->mDocument.getPhysics()), mSceneManager(parent->getSceneManager())
, mCurrentObj(""), mMouseState(Mouse_Default), mOldPos(0,0), mMouseEventTimer(0), mPlane(0) , mCurrentObj(""), mMouseState(Mouse_Default), mOldPos(0,0), mMouseEventTimer(0), mPlane(0)
, mGrabbedSceneNode(""), mOrigObjPos(Ogre::Vector3()), mOrigMousePos(Ogre::Vector3()) , mGrabbedSceneNode(""), mOrigObjPos(Ogre::Vector3()), mOrigMousePos(Ogre::Vector3())
, mCurrentMousePos(Ogre::Vector3()), mOffset(0.0f) , mCurrentMousePos(Ogre::Vector3()), mOffset(0.0f)
@ -255,7 +255,7 @@ namespace CSVRender
std::pair<std::string, Ogre::Vector3> result = terrainUnderCursor(event->x(), event->y()); std::pair<std::string, Ogre::Vector3> result = terrainUnderCursor(event->x(), event->y());
if(result.first != "") if(result.first != "")
{ {
// FIXME: terrain editing // FIXME: terrain editing goes here
} }
break; break;
} }
@ -267,6 +267,8 @@ namespace CSVRender
void MouseState::mouseDoubleClickEvent (QMouseEvent *event) void MouseState::mouseDoubleClickEvent (QMouseEvent *event)
{ {
event->ignore(); event->ignore();
//mPhysics->toggleDebugRendering(mSceneManager);
//mParent->flagAsModified();
} }
bool MouseState::wheelEvent (QWheelEvent *event) bool MouseState::wheelEvent (QWheelEvent *event)

View file

@ -2,6 +2,7 @@
#define OPENCS_VIEW_MOUSESTATE_H #define OPENCS_VIEW_MOUSESTATE_H
#include <map> #include <map>
#include <boost/shared_ptr.hpp>
#include <QPoint> #include <QPoint>
#include <OgreVector3.h> #include <OgreVector3.h>
@ -43,7 +44,7 @@ namespace CSVRender
MouseStates mMouseState; MouseStates mMouseState;
WorldspaceWidget *mParent; WorldspaceWidget *mParent;
CSVWorld::PhysicsSystem *mPhysics; // local copy boost::shared_ptr<CSVWorld::PhysicsSystem> mPhysics;
Ogre::SceneManager *mSceneManager; // local copy Ogre::SceneManager *mSceneManager; // local copy
QPoint mOldPos; QPoint mOldPos;

View file

@ -44,11 +44,12 @@ bool CSVRender::Navigation1st::mouseMoved (const QPoint& delta, int mode)
float deltaPitch = getFactor (true) * delta.y(); float deltaPitch = getFactor (true) * delta.y();
Ogre::Radian newPitch = oldPitch + Ogre::Degree (deltaPitch); Ogre::Radian newPitch = oldPitch + Ogre::Degree (deltaPitch);
Ogre::Radian limit (Ogre::Math::PI/2-0.5); if ((deltaPitch>0 && newPitch<Ogre::Radian(Ogre::Math::PI-0.5)) ||
(deltaPitch<0 && newPitch>Ogre::Radian(0.5)))
if ((deltaPitch>0 && newPitch<limit) || (deltaPitch<0 && newPitch>-limit)) {
mCamera->pitch (Ogre::Degree (deltaPitch)); mCamera->pitch (Ogre::Degree (deltaPitch));
} }
}
return true; return true;
} }

View file

@ -132,7 +132,7 @@ const CSMWorld::CellRef& CSVRender::Object::getReference() const
} }
CSVRender::Object::Object (const CSMWorld::Data& data, Ogre::SceneNode *cellNode, CSVRender::Object::Object (const CSMWorld::Data& data, Ogre::SceneNode *cellNode,
const std::string& id, bool referenceable, CSVWorld::PhysicsSystem *physics, const std::string& id, bool referenceable, boost::shared_ptr<CSVWorld::PhysicsSystem> physics,
bool forceBaseToZero) bool forceBaseToZero)
: mData (data), mBase (0), mForceBaseToZero (forceBaseToZero), mPhysics(physics) : mData (data), mBase (0), mForceBaseToZero (forceBaseToZero), mPhysics(physics)
{ {
@ -156,6 +156,7 @@ CSVRender::Object::~Object()
{ {
clear(); clear();
if(mPhysics) // preview may not have physics enabled
mPhysics->removeObject(mBase->getName()); mPhysics->removeObject(mBase->getName());
if (mBase) if (mBase)

View file

@ -1,6 +1,8 @@
#ifndef OPENCS_VIEW_OBJECT_H #ifndef OPENCS_VIEW_OBJECT_H
#define OPENCS_VIEW_OBJECT_H #define OPENCS_VIEW_OBJECT_H
#include <boost/shared_ptr.hpp>
#include <components/nifogre/ogrenifloader.hpp> #include <components/nifogre/ogrenifloader.hpp>
class QModelIndex; class QModelIndex;
@ -31,7 +33,7 @@ namespace CSVRender
Ogre::SceneNode *mBase; Ogre::SceneNode *mBase;
NifOgre::ObjectScenePtr mObject; NifOgre::ObjectScenePtr mObject;
bool mForceBaseToZero; bool mForceBaseToZero;
CSVWorld::PhysicsSystem *mPhysics; boost::shared_ptr<CSVWorld::PhysicsSystem> mPhysics;
/// Not implemented /// Not implemented
Object (const Object&); Object (const Object&);
@ -58,7 +60,8 @@ namespace CSVRender
Object (const CSMWorld::Data& data, Ogre::SceneNode *cellNode, Object (const CSMWorld::Data& data, Ogre::SceneNode *cellNode,
const std::string& id, bool referenceable, const std::string& id, bool referenceable,
CSVWorld::PhysicsSystem *physics = NULL, bool forceBaseToZero = false); boost::shared_ptr<CSVWorld::PhysicsSystem> physics = boost::shared_ptr<CSVWorld::PhysicsSystem> (),
bool forceBaseToZero = false);
/// \param forceBaseToZero If this is a reference ignore the coordinates and place /// \param forceBaseToZero If this is a reference ignore the coordinates and place
/// it at 0, 0, 0 instead. /// it at 0, 0, 0 instead.

View file

@ -21,7 +21,10 @@
#include "../../model/world/idtable.hpp" #include "../../model/world/idtable.hpp"
#include "../widget/scenetooltoggle.hpp" #include "../widget/scenetooltoggle.hpp"
#include "../widget/scenetoolmode.hpp"
#include "../widget/scenetooltoggle2.hpp"
#include "editmode.hpp"
#include "elements.hpp" #include "elements.hpp"
bool CSVRender::PagedWorldspaceWidget::adjustCells() bool CSVRender::PagedWorldspaceWidget::adjustCells()
@ -109,7 +112,7 @@ bool CSVRender::PagedWorldspaceWidget::adjustCells()
mCells.find (*iter)==mCells.end()) mCells.find (*iter)==mCells.end())
{ {
Cell *cell = new Cell (mDocument.getData(), getSceneManager(), Cell *cell = new Cell (mDocument.getData(), getSceneManager(),
iter->getId (mWorldspace), getPhysics()); iter->getId (mWorldspace), mDocument.getPhysics());
mCells.insert (std::make_pair (*iter, cell)); mCells.insert (std::make_pair (*iter, cell));
float height = cell->getTerrainHeightAt(Ogre::Vector3( float height = cell->getTerrainHeightAt(Ogre::Vector3(
@ -210,6 +213,34 @@ void CSVRender::PagedWorldspaceWidget::mouseDoubleClickEvent (QMouseEvent *event
WorldspaceWidget::mouseDoubleClickEvent(event); WorldspaceWidget::mouseDoubleClickEvent(event);
} }
void CSVRender::PagedWorldspaceWidget::addVisibilitySelectorButtons (
CSVWidget::SceneToolToggle2 *tool)
{
WorldspaceWidget::addVisibilitySelectorButtons (tool);
tool->addButton (Element_Terrain, "Terrain");
tool->addButton (Element_Fog, "Fog", "", true);
}
void CSVRender::PagedWorldspaceWidget::addEditModeSelectorButtons (
CSVWidget::SceneToolMode *tool)
{
WorldspaceWidget::addEditModeSelectorButtons (tool);
/// \todo replace EditMode with suitable subclasses
tool->addButton (
new EditMode (this, QIcon (":placeholder"), Element_Reference, "Terrain shape editing"),
"terrain-shape");
tool->addButton (
new EditMode (this, QIcon (":placeholder"), Element_Reference, "Terrain texture editing"),
"terrain-texture");
tool->addButton (
new EditMode (this, QIcon (":placeholder"), Element_Reference, "Terrain vertex paint editing"),
"terrain-vertex");
tool->addButton (
new EditMode (this, QIcon (":placeholder"), Element_Reference, "Terrain movement"),
"terrain-move");
}
void CSVRender::PagedWorldspaceWidget::updateOverlay() void CSVRender::PagedWorldspaceWidget::updateOverlay()
{ {
if(getCamera()->getViewport()) if(getCamera()->getViewport())
@ -340,8 +371,11 @@ CSVRender::PagedWorldspaceWidget::~PagedWorldspaceWidget()
delete iter->second; delete iter->second;
} }
if(mOverlayMask)
{
removeRenderTargetListener(mOverlayMask); removeRenderTargetListener(mOverlayMask);
delete mOverlayMask; delete mOverlayMask;
}
} }
void CSVRender::PagedWorldspaceWidget::useViewHint (const std::string& hint) void CSVRender::PagedWorldspaceWidget::useViewHint (const std::string& hint)
@ -445,21 +479,21 @@ CSVRender::WorldspaceWidget::dropRequirments CSVRender::PagedWorldspaceWidget::g
} }
} }
unsigned int CSVRender::PagedWorldspaceWidget::getElementMask() const unsigned int CSVRender::PagedWorldspaceWidget::getVisibilityMask() const
{ {
return WorldspaceWidget::getElementMask() | mControlElements->getSelection(); return WorldspaceWidget::getVisibilityMask() | mControlElements->getSelection();
} }
CSVWidget::SceneToolToggle *CSVRender::PagedWorldspaceWidget::makeControlVisibilitySelector ( CSVWidget::SceneToolToggle *CSVRender::PagedWorldspaceWidget::makeControlVisibilitySelector (
CSVWidget::SceneToolbar *parent) CSVWidget::SceneToolbar *parent)
{ {
mControlElements = new CSVWidget::SceneToolToggle (parent, mControlElements = new CSVWidget::SceneToolToggle (parent,
"Controls & Guides Visibility", ":door.png"); "Controls & Guides Visibility", ":placeholder");
mControlElements->addButton (":activator.png", Element_CellMarker, ":activator.png", mControlElements->addButton (":placeholder", Element_CellMarker, ":placeholder",
"Cell marker"); "Cell marker");
mControlElements->addButton (":armor.png", Element_CellArrow, ":armor.png", "Cell arrows"); mControlElements->addButton (":placeholder", Element_CellArrow, ":placeholder", "Cell arrows");
mControlElements->addButton (":armor.png", Element_CellBorder, ":armor.png", "Cell border"); mControlElements->addButton (":placeholder", Element_CellBorder, ":placeholder", "Cell border");
mControlElements->setSelection (0xffffffff); mControlElements->setSelection (0xffffffff);

View file

@ -8,9 +8,13 @@
#include "worldspacewidget.hpp" #include "worldspacewidget.hpp"
#include "cell.hpp" #include "cell.hpp"
namespace CSVWidget
{
class SceneToolToggle;
}
namespace CSVRender namespace CSVRender
{ {
class TextOverlay; class TextOverlay;
class OverlayMask; class OverlayMask;
@ -75,10 +79,14 @@ namespace CSVRender
virtual CSVWidget::SceneToolToggle *makeControlVisibilitySelector ( virtual CSVWidget::SceneToolToggle *makeControlVisibilitySelector (
CSVWidget::SceneToolbar *parent); CSVWidget::SceneToolbar *parent);
virtual unsigned int getElementMask() const; virtual unsigned int getVisibilityMask() const;
protected: protected:
virtual void addVisibilitySelectorButtons (CSVWidget::SceneToolToggle2 *tool);
virtual void addEditModeSelectorButtons (CSVWidget::SceneToolMode *tool);
virtual void updateOverlay(); virtual void updateOverlay();
virtual void mousePressEvent (QMouseEvent *event); virtual void mousePressEvent (QMouseEvent *event);

View file

@ -10,7 +10,7 @@
CSVRender::PreviewWidget::PreviewWidget (CSMWorld::Data& data, CSVRender::PreviewWidget::PreviewWidget (CSMWorld::Data& data,
const std::string& id, bool referenceable, QWidget *parent) const std::string& id, bool referenceable, QWidget *parent)
: SceneWidget (parent), mData (data), : SceneWidget (parent), mData (data),
mObject (data, getSceneManager()->getRootSceneNode(), id, referenceable, NULL, true) mObject (data, getSceneManager()->getRootSceneNode(), id, referenceable, boost::shared_ptr<CSVWorld::PhysicsSystem>(), true)
{ {
setNavigation (&mOrbit); setNavigation (&mOrbit);

View file

@ -79,7 +79,7 @@ TextOverlay::TextOverlay(const Ogre::MovableObject* obj, const Ogre::Camera* cam
pixelBuffer->lock(Ogre::HardwareBuffer::HBL_NORMAL); pixelBuffer->lock(Ogre::HardwareBuffer::HBL_NORMAL);
const Ogre::PixelBox& pixelBox = pixelBuffer->getCurrentLock(); const Ogre::PixelBox& pixelBox = pixelBuffer->getCurrentLock();
uint8_t* pDest = static_cast<uint8_t*>(pixelBox.data); Ogre::uint8* pDest = static_cast<Ogre::uint8*>(pixelBox.data);
// Fill in some pixel data. This will give a semi-transparent blue, // Fill in some pixel data. This will give a semi-transparent blue,
// but this is of course dependent on the chosen pixel format. // but this is of course dependent on the chosen pixel format.

View file

@ -15,6 +15,7 @@
#include "../../model/world/tablemimedata.hpp" #include "../../model/world/tablemimedata.hpp"
#include "../widget/scenetooltoggle.hpp" #include "../widget/scenetooltoggle.hpp"
#include "../widget/scenetooltoggle2.hpp"
#include "elements.hpp" #include "elements.hpp"
@ -32,14 +33,6 @@ void CSVRender::UnpagedWorldspaceWidget::update()
flagAsModified(); flagAsModified();
} }
void CSVRender::UnpagedWorldspaceWidget::addVisibilitySelectorButtons (
CSVWidget::SceneToolToggle *tool)
{
WorldspaceWidget::addVisibilitySelectorButtons (tool);
tool->addButton (":armor.png", Element_Fog, ":armor.png", "Fog");
}
CSVRender::UnpagedWorldspaceWidget::UnpagedWorldspaceWidget (const std::string& cellId, CSMDoc::Document& document, QWidget* parent) CSVRender::UnpagedWorldspaceWidget::UnpagedWorldspaceWidget (const std::string& cellId, CSMDoc::Document& document, QWidget* parent)
: WorldspaceWidget (document, parent), mCellId (cellId) : WorldspaceWidget (document, parent), mCellId (cellId)
{ {
@ -56,7 +49,7 @@ CSVRender::UnpagedWorldspaceWidget::UnpagedWorldspaceWidget (const std::string&
update(); update();
mCell.reset (new Cell (document.getData(), getSceneManager(), mCellId, getPhysics())); mCell.reset (new Cell (document.getData(), getSceneManager(), mCellId, document.getPhysics()));
} }
void CSVRender::UnpagedWorldspaceWidget::cellDataChanged (const QModelIndex& topLeft, void CSVRender::UnpagedWorldspaceWidget::cellDataChanged (const QModelIndex& topLeft,
@ -98,7 +91,7 @@ bool CSVRender::UnpagedWorldspaceWidget::handleDrop (const std::vector<CSMWorld:
return false; return false;
mCellId = data.begin()->getId(); mCellId = data.begin()->getId();
mCell.reset (new Cell (getDocument().getData(), getSceneManager(), mCellId, getPhysics())); mCell.reset (new Cell (getDocument().getData(), getSceneManager(), mCellId, getDocument().getPhysics()));
update(); update();
emit cellChanged(*data.begin()); emit cellChanged(*data.begin());
@ -160,6 +153,14 @@ void CSVRender::UnpagedWorldspaceWidget::referenceAdded (const QModelIndex& pare
flagAsModified(); flagAsModified();
} }
void CSVRender::UnpagedWorldspaceWidget::addVisibilitySelectorButtons (
CSVWidget::SceneToolToggle2 *tool)
{
WorldspaceWidget::addVisibilitySelectorButtons (tool);
tool->addButton (Element_Terrain, "Terrain", "", true);
tool->addButton (Element_Fog, "Fog");
}
std::string CSVRender::UnpagedWorldspaceWidget::getStartupInstruction() std::string CSVRender::UnpagedWorldspaceWidget::getStartupInstruction()
{ {
Ogre::Vector3 position = getCamera()->getPosition(); Ogre::Vector3 position = getCamera()->getPosition();

View file

@ -32,10 +32,6 @@ namespace CSVRender
void update(); void update();
protected:
virtual void addVisibilitySelectorButtons (CSVWidget::SceneToolToggle *tool);
public: public:
UnpagedWorldspaceWidget (const std::string& cellId, CSMDoc::Document& document, UnpagedWorldspaceWidget (const std::string& cellId, CSMDoc::Document& document,
@ -64,6 +60,10 @@ namespace CSVRender
virtual std::string getStartupInstruction(); virtual std::string getStartupInstruction();
protected:
virtual void addVisibilitySelectorButtons (CSVWidget::SceneToolToggle2 *tool);
private slots: private slots:
void cellDataChanged (const QModelIndex& topLeft, const QModelIndex& bottomRight); void cellDataChanged (const QModelIndex& topLeft, const QModelIndex& bottomRight);

View file

@ -13,16 +13,17 @@
#include "../../model/world/idtable.hpp" #include "../../model/world/idtable.hpp"
#include "../widget/scenetoolmode.hpp" #include "../widget/scenetoolmode.hpp"
#include "../widget/scenetooltoggle.hpp" #include "../widget/scenetooltoggle2.hpp"
#include "../widget/scenetoolrun.hpp" #include "../widget/scenetoolrun.hpp"
#include "../world/physicsmanager.hpp"
#include "../world/physicssystem.hpp" #include "../world/physicssystem.hpp"
#include "elements.hpp" #include "elements.hpp"
#include "editmode.hpp"
CSVRender::WorldspaceWidget::WorldspaceWidget (CSMDoc::Document& document, QWidget* parent) CSVRender::WorldspaceWidget::WorldspaceWidget (CSMDoc::Document& document, QWidget* parent)
: SceneWidget (parent), mDocument(document), mSceneElements(0), mRun(0), mPhysics(0), mMouse(0) : SceneWidget (parent), mDocument(document), mSceneElements(0), mRun(0), mPhysics(boost::shared_ptr<CSVWorld::PhysicsSystem>()), mMouse(0),
mInteractionMask (0)
{ {
setAcceptDrops(true); setAcceptDrops(true);
@ -54,9 +55,7 @@ CSVRender::WorldspaceWidget::WorldspaceWidget (CSMDoc::Document& document, QWidg
connect (debugProfiles, SIGNAL (rowsAboutToBeRemoved (const QModelIndex&, int, int)), connect (debugProfiles, SIGNAL (rowsAboutToBeRemoved (const QModelIndex&, int, int)),
this, SLOT (debugProfileAboutToBeRemoved (const QModelIndex&, int, int))); this, SLOT (debugProfileAboutToBeRemoved (const QModelIndex&, int, int)));
// associate WorldSpaceWidgets (and their SceneManagers) with Documents mPhysics = document.getPhysics(); // create physics if one doesn't exist
// then create physics if there is a new document
mPhysics = CSVWorld::PhysicsManager::instance()->addSceneWidget(document, this);
mPhysics->addSceneManager(getSceneManager(), this); mPhysics->addSceneManager(getSceneManager(), this);
mMouse = new MouseState(this); mMouse = new MouseState(this);
} }
@ -65,7 +64,6 @@ CSVRender::WorldspaceWidget::~WorldspaceWidget ()
{ {
delete mMouse; delete mMouse;
mPhysics->removeSceneManager(getSceneManager()); mPhysics->removeSceneManager(getSceneManager());
CSVWorld::PhysicsManager::instance()->removeSceneWidget(this);
} }
void CSVRender::WorldspaceWidget::selectNavigationMode (const std::string& mode) void CSVRender::WorldspaceWidget::selectNavigationMode (const std::string& mode)
@ -125,10 +123,10 @@ CSVWidget::SceneToolMode *CSVRender::WorldspaceWidget::makeNavigationSelector (
return tool; return tool;
} }
CSVWidget::SceneToolToggle *CSVRender::WorldspaceWidget::makeSceneVisibilitySelector (CSVWidget::SceneToolbar *parent) CSVWidget::SceneToolToggle2 *CSVRender::WorldspaceWidget::makeSceneVisibilitySelector (CSVWidget::SceneToolbar *parent)
{ {
mSceneElements= new CSVWidget::SceneToolToggle (parent, mSceneElements = new CSVWidget::SceneToolToggle2 (parent,
"Scene Element Visibility", ":door.png"); "Scene Element Visibility", ":scenetoolbar/scene-view-c", ":scenetoolbar/scene-view-");
addVisibilitySelectorButtons (mSceneElements); addVisibilitySelectorButtons (mSceneElements);
@ -170,7 +168,7 @@ CSVWidget::SceneToolRun *CSVRender::WorldspaceWidget::makeRunTool (
std::sort (profiles.begin(), profiles.end()); std::sort (profiles.begin(), profiles.end());
mRun = new CSVWidget::SceneToolRun (parent, "Run OpenMW from the current camera position", mRun = new CSVWidget::SceneToolRun (parent, "Run OpenMW from the current camera position",
":door.png", ":faction.png", profiles); ":scenetoolbar/play", profiles);
connect (mRun, SIGNAL (runRequest (const std::string&)), connect (mRun, SIGNAL (runRequest (const std::string&)),
this, SLOT (runRequest (const std::string&))); this, SLOT (runRequest (const std::string&)));
@ -178,6 +176,16 @@ CSVWidget::SceneToolRun *CSVRender::WorldspaceWidget::makeRunTool (
return mRun; return mRun;
} }
CSVWidget::SceneToolMode *CSVRender::WorldspaceWidget::makeEditModeSelector (
CSVWidget::SceneToolbar *parent)
{
CSVWidget::SceneToolMode *tool = new CSVWidget::SceneToolMode (parent, "Edit Mode");
addEditModeSelectorButtons (tool);
return tool;
}
CSVRender::WorldspaceWidget::DropType CSVRender::WorldspaceWidget::getDropType ( CSVRender::WorldspaceWidget::DropType CSVRender::WorldspaceWidget::getDropType (
const std::vector< CSMWorld::UniversalId >& data) const std::vector< CSMWorld::UniversalId >& data)
{ {
@ -232,18 +240,38 @@ bool CSVRender::WorldspaceWidget::handleDrop (const std::vector<CSMWorld::Univer
return false; return false;
} }
unsigned int CSVRender::WorldspaceWidget::getElementMask() const unsigned int CSVRender::WorldspaceWidget::getVisibilityMask() const
{ {
return mSceneElements->getSelection(); return mSceneElements->getSelection();
} }
void CSVRender::WorldspaceWidget::addVisibilitySelectorButtons ( void CSVRender::WorldspaceWidget::setInteractionMask (unsigned int mask)
CSVWidget::SceneToolToggle *tool)
{ {
tool->addButton (":activator.png", Element_Reference, ":activator.png", "References"); mInteractionMask = mask | Element_CellMarker | Element_CellArrow;
tool->addButton (":armor.png", Element_Terrain, ":armor.png", "Terrain"); }
tool->addButton (":armor.png", Element_Water, ":armor.png", "Water");
tool->addButton (":armor.png", Element_Pathgrid, ":armor.png", "Pathgrid"); unsigned int CSVRender::WorldspaceWidget::getInteractionMask() const
{
return mInteractionMask & getVisibilityMask();
}
void CSVRender::WorldspaceWidget::addVisibilitySelectorButtons (
CSVWidget::SceneToolToggle2 *tool)
{
tool->addButton (Element_Reference, "References");
tool->addButton (Element_Water, "Water");
tool->addButton (Element_Pathgrid, "Pathgrid");
}
void CSVRender::WorldspaceWidget::addEditModeSelectorButtons (CSVWidget::SceneToolMode *tool)
{
/// \todo replace EditMode with suitable subclasses
tool->addButton (
new EditMode (this, QIcon (":placeholder"), Element_Reference, "Reference editing"),
"object");
tool->addButton (
new EditMode (this, QIcon (":placeholder"), Element_Pathgrid, "Pathgrid editing"),
"pathgrid");
} }
CSMDoc::Document& CSVRender::WorldspaceWidget::getDocument() CSMDoc::Document& CSVRender::WorldspaceWidget::getDocument()
@ -327,7 +355,7 @@ void CSVRender::WorldspaceWidget::debugProfileAboutToBeRemoved (const QModelInde
void CSVRender::WorldspaceWidget::elementSelectionChanged() void CSVRender::WorldspaceWidget::elementSelectionChanged()
{ {
setVisibilityMask (getElementMask()); setVisibilityMask (getVisibilityMask());
flagAsModified(); flagAsModified();
updateOverlay(); updateOverlay();
} }
@ -336,12 +364,6 @@ void CSVRender::WorldspaceWidget::updateOverlay()
{ {
} }
CSVWorld::PhysicsSystem *CSVRender::WorldspaceWidget::getPhysics()
{
assert(mPhysics);
return mPhysics;
}
void CSVRender::WorldspaceWidget::mouseMoveEvent (QMouseEvent *event) void CSVRender::WorldspaceWidget::mouseMoveEvent (QMouseEvent *event)
{ {
if(event->buttons() & Qt::RightButton) if(event->buttons() & Qt::RightButton)

View file

@ -1,6 +1,8 @@
#ifndef OPENCS_VIEW_WORLDSPACEWIDGET_H #ifndef OPENCS_VIEW_WORLDSPACEWIDGET_H
#define OPENCS_VIEW_WORLDSPACEWIDGET_H #define OPENCS_VIEW_WORLDSPACEWIDGET_H
#include <boost/shared_ptr.hpp>
#include "scenewidget.hpp" #include "scenewidget.hpp"
#include "mousestate.hpp" #include "mousestate.hpp"
@ -18,7 +20,7 @@ namespace CSMWorld
namespace CSVWidget namespace CSVWidget
{ {
class SceneToolMode; class SceneToolMode;
class SceneToolToggle; class SceneToolToggle2;
class SceneToolbar; class SceneToolbar;
class SceneToolRun; class SceneToolRun;
} }
@ -37,11 +39,12 @@ namespace CSVRender
CSVRender::Navigation1st m1st; CSVRender::Navigation1st m1st;
CSVRender::NavigationFree mFree; CSVRender::NavigationFree mFree;
CSVRender::NavigationOrbit mOrbit; CSVRender::NavigationOrbit mOrbit;
CSVWidget::SceneToolToggle *mSceneElements; CSVWidget::SceneToolToggle2 *mSceneElements;
CSVWidget::SceneToolRun *mRun; CSVWidget::SceneToolRun *mRun;
CSMDoc::Document& mDocument; CSMDoc::Document& mDocument;
CSVWorld::PhysicsSystem *mPhysics; boost::shared_ptr<CSVWorld::PhysicsSystem> mPhysics;
MouseState *mMouse; MouseState *mMouse;
unsigned int mInteractionMask;
public: public:
@ -70,13 +73,17 @@ namespace CSVRender
/// \attention The created tool is not added to the toolbar (via addTool). Doing /// \attention The created tool is not added to the toolbar (via addTool). Doing
/// that is the responsibility of the calling function. /// that is the responsibility of the calling function.
CSVWidget::SceneToolToggle *makeSceneVisibilitySelector ( CSVWidget::SceneToolToggle2 *makeSceneVisibilitySelector (
CSVWidget::SceneToolbar *parent); CSVWidget::SceneToolbar *parent);
/// \attention The created tool is not added to the toolbar (via addTool). Doing /// \attention The created tool is not added to the toolbar (via addTool). Doing
/// that is the responsibility of the calling function. /// that is the responsibility of the calling function.
CSVWidget::SceneToolRun *makeRunTool (CSVWidget::SceneToolbar *parent); CSVWidget::SceneToolRun *makeRunTool (CSVWidget::SceneToolbar *parent);
/// \attention The created tool is not added to the toolbar (via addTool). Doing
/// that is the responsibility of the calling function.
CSVWidget::SceneToolMode *makeEditModeSelector (CSVWidget::SceneToolbar *parent);
void selectDefaultNavigationMode(); void selectDefaultNavigationMode();
static DropType getDropType(const std::vector<CSMWorld::UniversalId>& data); static DropType getDropType(const std::vector<CSMWorld::UniversalId>& data);
@ -90,18 +97,26 @@ namespace CSVRender
virtual bool handleDrop (const std::vector<CSMWorld::UniversalId>& data, virtual bool handleDrop (const std::vector<CSMWorld::UniversalId>& data,
DropType type); DropType type);
virtual unsigned int getElementMask() const; virtual unsigned int getVisibilityMask() const;
/// \note This function will implicitly add elements that are independent of the
/// selected edit mode.
virtual void setInteractionMask (unsigned int mask);
/// \note This function will only return those elements that are both visible and
/// marked for interaction.
unsigned int getInteractionMask() const;
protected: protected:
virtual void addVisibilitySelectorButtons (CSVWidget::SceneToolToggle *tool); virtual void addVisibilitySelectorButtons (CSVWidget::SceneToolToggle2 *tool);
virtual void addEditModeSelectorButtons (CSVWidget::SceneToolMode *tool);
CSMDoc::Document& getDocument(); CSMDoc::Document& getDocument();
virtual void updateOverlay(); virtual void updateOverlay();
CSVWorld::PhysicsSystem *getPhysics();
virtual void mouseMoveEvent (QMouseEvent *event); virtual void mouseMoveEvent (QMouseEvent *event);
virtual void mousePressEvent (QMouseEvent *event); virtual void mousePressEvent (QMouseEvent *event);
virtual void mouseReleaseEvent (QMouseEvent *event); virtual void mouseReleaseEvent (QMouseEvent *event);

View file

@ -1,31 +1,15 @@
#include "reportsubview.hpp" #include "reportsubview.hpp"
#include <QTableView> #include "reporttable.hpp"
#include <QHeaderView>
#include "../../model/tools/reportmodel.hpp"
#include "../../view/world/idtypedelegate.hpp"
CSVTools::ReportSubView::ReportSubView (const CSMWorld::UniversalId& id, CSMDoc::Document& document) CSVTools::ReportSubView::ReportSubView (const CSMWorld::UniversalId& id, CSMDoc::Document& document)
: CSVDoc::SubView (id), mModel (document.getReport (id)) : CSVDoc::SubView (id)
{ {
setWidget (mTable = new QTableView (this)); setWidget (mTable = new ReportTable (document, id, this));
mTable->setModel (mModel);
mTable->horizontalHeader()->setResizeMode (QHeaderView::Interactive); connect (mTable, SIGNAL (editRequest (const CSMWorld::UniversalId&, const std::string&)),
mTable->verticalHeader()->hide(); SIGNAL (focusId (const CSMWorld::UniversalId&, const std::string&)));
mTable->setSortingEnabled (true);
mTable->setSelectionBehavior (QAbstractItemView::SelectRows);
mTable->setSelectionMode (QAbstractItemView::ExtendedSelection);
mIdTypeDelegate = CSVWorld::IdTypeDelegateFactory().makeDelegate (
document, this);
mTable->setItemDelegateForColumn (0, mIdTypeDelegate);
connect (mTable, SIGNAL (doubleClicked (const QModelIndex&)), this, SLOT (show (const QModelIndex&)));
} }
void CSVTools::ReportSubView::setEditLock (bool locked) void CSVTools::ReportSubView::setEditLock (bool locked)
@ -33,13 +17,7 @@ void CSVTools::ReportSubView::setEditLock (bool locked)
// ignored. We don't change document state anyway. // ignored. We don't change document state anyway.
} }
void CSVTools::ReportSubView::updateUserSetting void CSVTools::ReportSubView::updateUserSetting (const QString &name, const QStringList &list)
(const QString &name, const QStringList &list)
{ {
mIdTypeDelegate->updateUserSetting (name, list); mTable->updateUserSetting (name, list);
}
void CSVTools::ReportSubView::show (const QModelIndex& index)
{
focusId (mModel->getUniversalId (index.row()), "");
} }

View file

@ -11,27 +11,15 @@ namespace CSMDoc
class Document; class Document;
} }
namespace CSMTools
{
class ReportModel;
}
namespace CSVWorld
{
class CommandDelegate;
}
namespace CSVTools namespace CSVTools
{ {
class Table; class ReportTable;
class ReportSubView : public CSVDoc::SubView class ReportSubView : public CSVDoc::SubView
{ {
Q_OBJECT Q_OBJECT
CSMTools::ReportModel *mModel; ReportTable *mTable;
QTableView *mTable;
CSVWorld::CommandDelegate *mIdTypeDelegate;
public: public:
@ -39,12 +27,7 @@ namespace CSVTools
virtual void setEditLock (bool locked); virtual void setEditLock (bool locked);
virtual void updateUserSetting virtual void updateUserSetting (const QString &, const QStringList &);
(const QString &, const QStringList &);
private slots:
void show (const QModelIndex& index);
}; };
} }

View file

@ -0,0 +1,136 @@
#include "reporttable.hpp"
#include <algorithm>
#include <QHeaderView>
#include <QAction>
#include <QMenu>
#include "../../model/tools/reportmodel.hpp"
#include "../../view/world/idtypedelegate.hpp"
void CSVTools::ReportTable::contextMenuEvent (QContextMenuEvent *event)
{
QModelIndexList selectedRows = selectionModel()->selectedRows();
// create context menu
QMenu menu (this);
if (!selectedRows.empty())
{
menu.addAction (mShowAction);
menu.addAction (mRemoveAction);
}
menu.exec (event->globalPos());
}
void CSVTools::ReportTable::mouseMoveEvent (QMouseEvent *event)
{
if (event->buttons() & Qt::LeftButton)
startDrag (*this);
}
void CSVTools::ReportTable::mouseDoubleClickEvent (QMouseEvent *event)
{
Qt::KeyboardModifiers modifiers =
event->modifiers() & (Qt::ShiftModifier | Qt::ControlModifier);
QModelIndex index = currentIndex();
selectionModel()->select (index,
QItemSelectionModel::Clear | QItemSelectionModel::Select | QItemSelectionModel::Rows);
switch (modifiers)
{
case 0:
event->accept();
showSelection();
break;
case Qt::ShiftModifier:
event->accept();
removeSelection();
break;
case Qt::ControlModifier:
event->accept();
showSelection();
removeSelection();
break;
}
}
CSVTools::ReportTable::ReportTable (CSMDoc::Document& document,
const CSMWorld::UniversalId& id, QWidget *parent)
: CSVWorld::DragRecordTable (document, parent), mModel (document.getReport (id))
{
horizontalHeader()->setResizeMode (QHeaderView::Interactive);
verticalHeader()->hide();
setSortingEnabled (true);
setSelectionBehavior (QAbstractItemView::SelectRows);
setSelectionMode (QAbstractItemView::ExtendedSelection);
setModel (mModel);
setColumnHidden (2, true);
mIdTypeDelegate = CSVWorld::IdTypeDelegateFactory().makeDelegate (
document, this);
setItemDelegateForColumn (0, mIdTypeDelegate);
mShowAction = new QAction (tr ("Show"), this);
connect (mShowAction, SIGNAL (triggered()), this, SLOT (showSelection()));
addAction (mShowAction);
mRemoveAction = new QAction (tr ("Remove from list"), this);
connect (mRemoveAction, SIGNAL (triggered()), this, SLOT (removeSelection()));
addAction (mRemoveAction);
}
std::vector<CSMWorld::UniversalId> CSVTools::ReportTable::getDraggedRecords() const
{
std::vector<CSMWorld::UniversalId> ids;
QModelIndexList selectedRows = selectionModel()->selectedRows();
for (QModelIndexList::const_iterator iter (selectedRows.begin()); iter!=selectedRows.end();
++iter)
{
ids.push_back (mModel->getUniversalId (iter->row()));
}
return ids;
}
void CSVTools::ReportTable::updateUserSetting (const QString& name, const QStringList& list)
{
mIdTypeDelegate->updateUserSetting (name, list);
}
void CSVTools::ReportTable::showSelection()
{
QModelIndexList selectedRows = selectionModel()->selectedRows();
for (QModelIndexList::const_iterator iter (selectedRows.begin()); iter!=selectedRows.end();
++iter)
emit editRequest (mModel->getUniversalId (iter->row()), mModel->getHint (iter->row()));
}
void CSVTools::ReportTable::removeSelection()
{
QModelIndexList selectedRows = selectionModel()->selectedRows();
std::reverse (selectedRows.begin(), selectedRows.end());
for (QModelIndexList::const_iterator iter (selectedRows.begin()); iter!=selectedRows.end();
++iter)
mModel->removeRows (iter->row(), 1);
selectionModel()->clear();
}

View file

@ -0,0 +1,58 @@
#ifndef CSV_TOOLS_REPORTTABLE_H
#define CSV_TOOLS_REPORTTABLE_H
#include "../world/dragrecordtable.hpp"
class QAction;
namespace CSMTools
{
class ReportModel;
}
namespace CSVWorld
{
class CommandDelegate;
}
namespace CSVTools
{
class ReportTable : public CSVWorld::DragRecordTable
{
Q_OBJECT
CSMTools::ReportModel *mModel;
CSVWorld::CommandDelegate *mIdTypeDelegate;
QAction *mShowAction;
QAction *mRemoveAction;
private:
void contextMenuEvent (QContextMenuEvent *event);
void mouseMoveEvent (QMouseEvent *event);
virtual void mouseDoubleClickEvent (QMouseEvent *event);
public:
ReportTable (CSMDoc::Document& document, const CSMWorld::UniversalId& id,
QWidget *parent = 0);
virtual std::vector<CSMWorld::UniversalId> getDraggedRecords() const;
void updateUserSetting (const QString& name, const QStringList& list);
private slots:
void showSelection();
void removeSelection();
signals:
void editRequest (const CSMWorld::UniversalId& id, const std::string& hint);
};
}
#endif

View file

@ -0,0 +1,10 @@
#include "modebutton.hpp"
CSVWidget::ModeButton::ModeButton (const QIcon& icon, const QString& tooltip, QWidget *parent)
: PushButton (icon, Type_Mode, tooltip, parent)
{}
void CSVWidget::ModeButton::activate (SceneToolbar *toolbar) {}
void CSVWidget::ModeButton::deactivate (SceneToolbar *toolbar) {}

View file

@ -0,0 +1,28 @@
#ifndef CSV_WIDGET_MODEBUTTON_H
#define CSV_WIDGET_MODEBUTTON_H
#include "pushbutton.hpp"
namespace CSVWidget
{
class SceneToolbar;
/// \brief Specialist PushButton of Type_Mode for use in SceneToolMode
class ModeButton : public PushButton
{
Q_OBJECT
public:
ModeButton (const QIcon& icon, const QString& tooltip = "",
QWidget *parent = 0);
/// Default-Implementation: do nothing
virtual void activate (SceneToolbar *toolbar);
/// Default-Implementation: do nothing
virtual void deactivate (SceneToolbar *toolbar);
};
}
#endif

View file

@ -72,6 +72,11 @@ CSVWidget::PushButton::PushButton (const QIcon& icon, Type type, const QString&
QWidget *parent) QWidget *parent)
: QPushButton (icon, "", parent), mKeepOpen (false), mType (type), mToolTip (tooltip) : QPushButton (icon, "", parent), mKeepOpen (false), mType (type), mToolTip (tooltip)
{ {
if (type==Type_Mode || type==Type_Toggle)
{
setCheckable (true);
connect (this, SIGNAL (toggled (bool)), this, SLOT (checkedStateChanged (bool)));
}
setCheckable (type==Type_Mode || type==Type_Toggle); setCheckable (type==Type_Mode || type==Type_Toggle);
setExtendedToolTip(); setExtendedToolTip();
} }
@ -97,3 +102,8 @@ CSVWidget::PushButton::Type CSVWidget::PushButton::getType() const
{ {
return mType; return mType;
} }
void CSVWidget::PushButton::checkedStateChanged (bool checked)
{
setExtendedToolTip();
}

View file

@ -53,6 +53,10 @@ namespace CSVWidget
QString getBaseToolTip() const; QString getBaseToolTip() const;
Type getType() const; Type getType() const;
private slots:
void checkedStateChanged (bool checked);
}; };
} }

View file

@ -31,9 +31,20 @@ CSVWidget::SceneToolbar::SceneToolbar (int buttonSize, QWidget *parent)
connect (focusScene, SIGNAL (activated()), this, SIGNAL (focusSceneRequest())); connect (focusScene, SIGNAL (activated()), this, SIGNAL (focusSceneRequest()));
} }
void CSVWidget::SceneToolbar::addTool (SceneTool *tool) void CSVWidget::SceneToolbar::addTool (SceneTool *tool, SceneTool *insertPoint)
{ {
if (!insertPoint)
mLayout->addWidget (tool, 0, Qt::AlignTop); mLayout->addWidget (tool, 0, Qt::AlignTop);
else
{
int index = mLayout->indexOf (insertPoint);
mLayout->insertWidget (index+1, tool, 0, Qt::AlignTop);
}
}
void CSVWidget::SceneToolbar::removeTool (SceneTool *tool)
{
mLayout->removeWidget (tool);
} }
int CSVWidget::SceneToolbar::getButtonSize() const int CSVWidget::SceneToolbar::getButtonSize() const

View file

@ -25,7 +25,11 @@ namespace CSVWidget
SceneToolbar (int buttonSize, QWidget *parent = 0); SceneToolbar (int buttonSize, QWidget *parent = 0);
void addTool (SceneTool *tool); /// If insertPoint==0, insert \a tool at the end of the scrollbar. Otherwise
/// insert tool after \a insertPoint.
void addTool (SceneTool *tool, SceneTool *insertPoint = 0);
void removeTool (SceneTool *tool);
int getButtonSize() const; int getButtonSize() const;

View file

@ -6,9 +6,9 @@
#include <QSignalMapper> #include <QSignalMapper>
#include "scenetoolbar.hpp" #include "scenetoolbar.hpp"
#include "pushbutton.hpp" #include "modebutton.hpp"
void CSVWidget::SceneToolMode::adjustToolTip (const PushButton *activeMode) void CSVWidget::SceneToolMode::adjustToolTip (const ModeButton *activeMode)
{ {
QString toolTip = mToolTip; QString toolTip = mToolTip;
@ -21,7 +21,7 @@ void CSVWidget::SceneToolMode::adjustToolTip (const PushButton *activeMode)
CSVWidget::SceneToolMode::SceneToolMode (SceneToolbar *parent, const QString& toolTip) CSVWidget::SceneToolMode::SceneToolMode (SceneToolbar *parent, const QString& toolTip)
: SceneTool (parent), mButtonSize (parent->getButtonSize()), mIconSize (parent->getIconSize()), : SceneTool (parent), mButtonSize (parent->getButtonSize()), mIconSize (parent->getIconSize()),
mToolTip (toolTip), mFirst (0) mToolTip (toolTip), mFirst (0), mCurrent (0), mToolbar (parent)
{ {
mPanel = new QFrame (this, Qt::Popup); mPanel = new QFrame (this, Qt::Popup);
@ -44,8 +44,14 @@ void CSVWidget::SceneToolMode::showPanel (const QPoint& position)
void CSVWidget::SceneToolMode::addButton (const std::string& icon, const std::string& id, void CSVWidget::SceneToolMode::addButton (const std::string& icon, const std::string& id,
const QString& tooltip) const QString& tooltip)
{ {
PushButton *button = new PushButton (QIcon (QPixmap (icon.c_str())), PushButton::Type_Mode, ModeButton *button = new ModeButton (QIcon (QPixmap (icon.c_str())), tooltip, mPanel);
tooltip, mPanel); addButton (button, id);
}
void CSVWidget::SceneToolMode::addButton (ModeButton *button, const std::string& id)
{
button->setParent (mPanel);
button->setSizePolicy (QSizePolicy (QSizePolicy::Fixed, QSizePolicy::Fixed)); button->setSizePolicy (QSizePolicy (QSizePolicy::Fixed, QSizePolicy::Fixed));
button->setIconSize (QSize (mIconSize, mIconSize)); button->setIconSize (QSize (mIconSize, mIconSize));
button->setFixedSize (mButtonSize, mButtonSize); button->setFixedSize (mButtonSize, mButtonSize);
@ -58,29 +64,40 @@ void CSVWidget::SceneToolMode::addButton (const std::string& icon, const std::st
if (mButtons.size()==1) if (mButtons.size()==1)
{ {
mFirst = button; mFirst = mCurrent = button;
setIcon (button->icon()); setIcon (button->icon());
button->setChecked (true); button->setChecked (true);
adjustToolTip (button); adjustToolTip (button);
mCurrent->activate (mToolbar);
} }
} }
void CSVWidget::SceneToolMode::selected() void CSVWidget::SceneToolMode::selected()
{ {
std::map<PushButton *, std::string>::const_iterator iter = std::map<ModeButton *, std::string>::const_iterator iter =
mButtons.find (dynamic_cast<PushButton *> (sender())); mButtons.find (dynamic_cast<ModeButton *> (sender()));
if (iter!=mButtons.end()) if (iter!=mButtons.end())
{ {
if (!iter->first->hasKeepOpen()) if (!iter->first->hasKeepOpen())
mPanel->hide(); mPanel->hide();
for (std::map<PushButton *, std::string>::const_iterator iter2 = mButtons.begin(); for (std::map<ModeButton *, std::string>::const_iterator iter2 = mButtons.begin();
iter2!=mButtons.end(); ++iter2) iter2!=mButtons.end(); ++iter2)
iter2->first->setChecked (iter2==iter); iter2->first->setChecked (iter2==iter);
setIcon (iter->first->icon()); setIcon (iter->first->icon());
adjustToolTip (iter->first); adjustToolTip (iter->first);
if (mCurrent!=iter->first)
{
if (mCurrent)
mCurrent->deactivate (mToolbar);
mCurrent = iter->first;
mCurrent->activate (mToolbar);
}
emit modeChanged (iter->second); emit modeChanged (iter->second);
} }
} }

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