From f2e2e15b319106e0ed362c6d4ca827519f04aafe Mon Sep 17 00:00:00 2001 From: danij Date: Wed, 12 Mar 2014 14:20:44 +0000 Subject: [PATCH 1/4] libdeng2|Record: Added an explicit setter for char const* Evidently some compilers (MSVC at least) interpret a zero-length, c-style string as bool, consequently resulting in a NumberValue rather than a TextValue being written to the Record. --- doomsday/libdeng2/include/de/data/record.h | 3 +++ doomsday/libdeng2/src/data/record.cpp | 9 +++++++++ 2 files changed, 12 insertions(+) diff --git a/doomsday/libdeng2/include/de/data/record.h b/doomsday/libdeng2/include/de/data/record.h index 238c0f4663..a1bffe459f 100644 --- a/doomsday/libdeng2/include/de/data/record.h +++ b/doomsday/libdeng2/include/de/data/record.h @@ -298,6 +298,9 @@ class DENG2_PUBLIC Record : public ISerializable, public LogEntry::Arg::Base, */ Variable &set(String const &name, bool value); + /// @copydoc set() + Variable &set(String const &name, char const *value); + /// @copydoc set() Variable &set(String const &name, Value::Text const &value); diff --git a/doomsday/libdeng2/src/data/record.cpp b/doomsday/libdeng2/src/data/record.cpp index 5c77b8f7e3..1d0398ec58 100644 --- a/doomsday/libdeng2/src/data/record.cpp +++ b/doomsday/libdeng2/src/data/record.cpp @@ -435,6 +435,15 @@ Variable &Record::set(String const &name, bool value) return addBoolean(name, value); } +Variable &Record::set(String const &name, char const *value) +{ + if(hasMember(name)) + { + return (*this)[name].set(TextValue(value)); + } + return addText(name, value); +} + Variable &Record::set(String const &name, Value::Text const &value) { if(hasMember(name)) From 15a257393688e97bb6e04a1eb131b2c058d7a262 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jaakko=20Ker=C3=A4nen?= Date: Thu, 13 Mar 2014 14:30:55 +0200 Subject: [PATCH 2/4] Windows|Debug|libgui: Don't assert GL operation success At shutdown, after restoring the original display mode, there was an OpenGL error occurring that caused a crash (assert dialog => recursive repaint?). --- doomsday/libgui/include/de/gui/libgui.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doomsday/libgui/include/de/gui/libgui.h b/doomsday/libgui/include/de/gui/libgui.h index 3dc8f9bc03..ad51e4bd93 100644 --- a/doomsday/libgui/include/de/gui/libgui.h +++ b/doomsday/libgui/include/de/gui/libgui.h @@ -43,7 +43,7 @@ #endif // Assertion specific to GL errors. -#ifdef Q_WS_X11 +#if defined(Q_WS_X11) || defined(WIN32) // Under X11 we're having more OpenGL errors; should investigate why. # define LIBGUI_ASSERT_GL(cond) // ignored #else From 0f4e30bb4fee352a83f5d50416eea31dc9bffe85 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jaakko=20Ker=C3=A4nen?= Date: Thu, 13 Mar 2014 14:10:26 +0200 Subject: [PATCH 3/4] Fixed|libdeng2: Copying a Record When making a copy of a record (or assigning one), subrecord ownership was not replicated correctly in the resulting instance. Added a test case in test_record to verify this behavior. --- doomsday/libdeng2/include/de/data/recordvalue.h | 5 +++-- doomsday/libdeng2/src/data/record.cpp | 16 ++++++++++++++++ doomsday/libdeng2/src/data/recordvalue.cpp | 6 +++--- doomsday/tests/test_record/main.cpp | 10 ++++++++++ 4 files changed, 32 insertions(+), 5 deletions(-) diff --git a/doomsday/libdeng2/include/de/data/recordvalue.h b/doomsday/libdeng2/include/de/data/recordvalue.h index d162963559..f593ac6eba 100644 --- a/doomsday/libdeng2/include/de/data/recordvalue.h +++ b/doomsday/libdeng2/include/de/data/recordvalue.h @@ -89,9 +89,10 @@ class DENG2_PUBLIC RecordValue : public Value, DENG2_OBSERVES(Record, Deletion) /** * Sets the record that the value is referencing. * - * @param record Record to reference. Ownership is not given. + * @param record Record to reference. Ownership is not given. + * @param ownership OwnsRecord, if the value is given ownership of @a record. */ - void setRecord(Record *record); + void setRecord(Record *record, OwnershipFlags ownership = 0); /** * Gives away ownership of the record, if the value owns the record. diff --git a/doomsday/libdeng2/src/data/record.cpp b/doomsday/libdeng2/src/data/record.cpp index 1d0398ec58..0800de8c6d 100644 --- a/doomsday/libdeng2/src/data/record.cpp +++ b/doomsday/libdeng2/src/data/record.cpp @@ -213,6 +213,22 @@ void Record::copyMembersFrom(Record const &other, CopyBehavior behavior) i.key().startsWith("__")) continue; Variable *var = new Variable(*i.value()); + + // Ownerships of copied subrecords should be retained in the copy. + if(RecordValue *recVal = var->value().maybeAs()) + { + DENG2_ASSERT(!recVal->hasOwnership()); // RecordValue duplication behavior + + RecordValue const &original = i.value()->value().as(); + if(original.hasOwnership()) + { + DENG2_ASSERT(recVal->record() == original.record()); + + // Make a true copy of the subrecord. + recVal->setRecord(new Record(*recVal->record()), RecordValue::OwnsRecord); + } + } + var->audienceForDeletion() += this; d->members[i.key()] = var; } diff --git a/doomsday/libdeng2/src/data/recordvalue.cpp b/doomsday/libdeng2/src/data/recordvalue.cpp index eb5856a675..2c68d1f1ee 100644 --- a/doomsday/libdeng2/src/data/recordvalue.cpp +++ b/doomsday/libdeng2/src/data/recordvalue.cpp @@ -62,7 +62,7 @@ bool RecordValue::usedToHaveOwnership() const return _oldOwnership.testFlag(OwnsRecord); } -void RecordValue::setRecord(Record *record) +void RecordValue::setRecord(Record *record, OwnershipFlags ownership) { if(record == _record) return; // Got it already. @@ -76,9 +76,9 @@ void RecordValue::setRecord(Record *record) } _record = record; - _ownership = 0; + _ownership = ownership; - if(_record) + if(_record && !_ownership.testFlag(OwnsRecord)) { // Since we don't own it, someone may delete the record. _record->audienceForDeletion() += this; diff --git a/doomsday/tests/test_record/main.cpp b/doomsday/tests/test_record/main.cpp index 3b629a9e46..8a71e93a1b 100644 --- a/doomsday/tests/test_record/main.cpp +++ b/doomsday/tests/test_record/main.cpp @@ -62,6 +62,16 @@ int main(int argc, char **argv) Reader(b) >> rec2; LOG_MSG("After being deserialized:\n") << rec2; + + Record before; + before.addRecord("subrecord"); + before.subrecord("subrecord").set("value", true); + DENG2_ASSERT(before.hasSubrecord("subrecord")); + LOG_MSG("Before copying:\n") << before; + + Record copied = before; + DENG2_ASSERT(copied.hasSubrecord("subrecord")); + LOG_MSG("Copied:\n") << copied; } catch(Error const &err) { From bd0a65dca50c8b617aeca37ace82a5f769ab8ce1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jaakko=20Ker=C3=A4nen?= Date: Thu, 13 Mar 2014 14:10:57 +0200 Subject: [PATCH 4/4] Tutorial|Client: Final tutorial step only needs the "Done" button --- doomsday/client/src/ui/widgets/consolewidget.cpp | 2 -- doomsday/client/src/ui/widgets/tutorialwidget.cpp | 12 ++++++++---- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/doomsday/client/src/ui/widgets/consolewidget.cpp b/doomsday/client/src/ui/widgets/consolewidget.cpp index fc4650d2dd..d7ff8f7d9f 100644 --- a/doomsday/client/src/ui/widgets/consolewidget.cpp +++ b/doomsday/client/src/ui/widgets/consolewidget.cpp @@ -43,8 +43,6 @@ using namespace de; static TimeDelta const LOG_OPEN_CLOSE_SPAN = 0.2; -static uint const POS_SCRIPT_MODE = 5; - DENG_GUI_PIMPL(ConsoleWidget), DENG2_OBSERVES(Variable, Change) { diff --git a/doomsday/client/src/ui/widgets/tutorialwidget.cpp b/doomsday/client/src/ui/widgets/tutorialwidget.cpp index f773481ee9..ce92626b1a 100644 --- a/doomsday/client/src/ui/widgets/tutorialwidget.cpp +++ b/doomsday/client/src/ui/widgets/tutorialwidget.cpp @@ -130,16 +130,20 @@ DENG_GUI_PIMPL(TutorialWidget) } current = s; + bool const isFinalStep = (current == Finish - 1); + dlg = new MessageDialog; dlg->useInfoStyle(); dlg->setDeleteAfterDismissed(true); dlg->setClickToClose(false); QObject::connect(dlg, SIGNAL(accepted(int)), thisPublic, SLOT(continueToNextStep())); QObject::connect(dlg, SIGNAL(rejected(int)), thisPublic, SLOT(stop())); - dlg->buttons() - << new DialogButtonItem(DialogWidget::Accept | DialogWidget::Default, - (current == Finish - 1)? tr("Done") : tr("Continue")) - << new DialogButtonItem(DialogWidget::Reject | DialogWidget::Action, tr("Skip Tutorial")); + dlg->buttons() << new DialogButtonItem(DialogWidget::Accept | DialogWidget::Default, + isFinalStep? tr("Done") : tr("Continue")); + if(!isFinalStep) + { + dlg->buttons() << new DialogButtonItem(DialogWidget::Reject | DialogWidget::Action, tr("Skip Tutorial")); + } // Insert the content for the dialog. ClientWindow &win = ClientWindow::main();