diff --git a/src/Wt/Dbo/QueryModel_impl.h b/src/Wt/Dbo/QueryModel_impl.h index 5a7772bd50..d1c61d17ff 100644 --- a/src/Wt/Dbo/QueryModel_impl.h +++ b/src/Wt/Dbo/QueryModel_impl.h @@ -171,21 +171,23 @@ bool QueryModel::setData(const WModelIndex& index, const boost::any& value, int role) { if (role == EditRole) { - Transaction transaction(query_.session()); + { + Transaction transaction(query_.session()); - Result& result = resultRow(index.row()); + Result& result = resultRow(index.row()); - int column = columns_[index.column()].fieldIdx_; + int column = columns_[index.column()].fieldIdx_; - const FieldInfo& field = fields()[column]; + const FieldInfo& field = fields()[column]; - boost::any dbValue = Wt::convertAnyToAny(value, *field.type()); + boost::any dbValue = Wt::convertAnyToAny(value, *field.type()); - query_result_traits::setValue(result, column, dbValue); + query_result_traits::setValue(result, column, dbValue); - invalidateRow(index.row()); + transaction.commit(); + } - transaction.commit(); + invalidateRow(index.row()); return true; } else diff --git a/src/Wt/WFileUpload b/src/Wt/WFileUpload index fa42802c9d..b156c18aa9 100644 --- a/src/Wt/WFileUpload +++ b/src/Wt/WFileUpload @@ -237,7 +237,7 @@ public: * \sa uploaded() * \sa WApplication::requestTooLarge() */ - Signal< ::int64_t >& fileTooLarge() { return fileTooLarge_; } + JSignal< ::int64_t >& fileTooLarge() { return fileTooLarge_; } /*! \brief %Signal emitted when the user selected a new file. * @@ -330,7 +330,7 @@ private: std::vector uploadedFiles_; - Signal< ::int64_t > fileTooLarge_; + JSignal< ::int64_t > fileTooLarge_; Signal< ::uint64_t, ::uint64_t > dataReceived_; @@ -354,9 +354,7 @@ protected: virtual void propagateSetEnabled(bool enabled); private: - void handleFileTooLarge(int fileSize); - - JSignal< ::int64_t > tooLarge_; + void handleFileTooLarge(::int64_t fileSize); void onUploaded(); diff --git a/src/Wt/WFileUpload.C b/src/Wt/WFileUpload.C index 4c00d5438f..f66b0230c3 100644 --- a/src/Wt/WFileUpload.C +++ b/src/Wt/WFileUpload.C @@ -76,15 +76,16 @@ protected: << "._p_.update(null, '" << fileUpload_->uploaded().encodeCmd() << "', null, true);"; } else { - o << "window.parent.postMessage(" - << "{ fu: '" << fileUpload_->id() << "'," + o << " window.parent.postMessage(" + << "JSON.stringify({ fu: '" << fileUpload_->id() << "'," << " signal: '" - << fileUpload_->uploaded().encodeCmd() << "'}, '*');"; + << fileUpload_->uploaded().encodeCmd() << "'}), '*');"; } } else if (request.tooLarge()) { LOG_DEBUG("Resource handleRequest(): signaling file-too-large"); - o << fileUpload_->tooLarge_.createCall(); + std::string s = boost::lexical_cast(request.tooLarge()); + o << fileUpload_->fileTooLarge().createCall(s); } } else { LOG_DEBUG("Resource handleRequest(): no signal"); @@ -94,11 +95,8 @@ protected: "" ""; - if (request.tooLarge()) - fileUpload_->tooLargeSize_ = request.tooLarge(); - else - if (!files.empty()) - fileUpload_->setFiles(files); + if (!request.tooLarge() && !files.empty()) + fileUpload_->setFiles(files); } private: @@ -118,14 +116,11 @@ const char *WFileUpload::UPLOADED_SIGNAL = "M_uploaded"; WFileUpload::WFileUpload(WContainerWidget *parent) : WWebWidget(parent), textSize_(20), - fileTooLarge_(this), + fileTooLarge_(this, "fileTooLarge"), dataReceived_(this), - progressBar_(0), - tooLarge_(this, "tooLargeSignal"), - tooLargeSize_(0) + progressBar_(0) { setInline(true); - tooLarge_.connect(boost::bind(&WFileUpload::handleFileTooLarge, this, _1)); create(); } @@ -181,7 +176,6 @@ void WFileUpload::onData(::uint64_t current, ::uint64_t total) + fileUploadTarget_->url() + "';"); if (flags_.test(BIT_UPLOADING)) { flags_.reset(BIT_UPLOADING); - tooLargeSize_ = dataExceeded; handleFileTooLarge(dataExceeded); WApplication *app = WApplication::instance(); @@ -237,7 +231,7 @@ EventSignal<>& WFileUpload::changed() return *voidEventSignal(CHANGE_SIGNAL, true); } -void WFileUpload::handleFileTooLarge(int fileSize) +void WFileUpload::handleFileTooLarge(::int64_t fileSize) { fileTooLarge().emit(fileSize); } @@ -316,16 +310,19 @@ void WFileUpload::updateDom(DomElement& element, bool all) std::string command = "{" - "debugger; \n" - "var x = " WT_CLASS ".$('in" + id() + "') \n" - " if (x.files != null) \n" - " for (var i = 0; i < x.files.length; i++) { \n" + "var x = " WT_CLASS ".$('in" + id() + "');" + " if (x.files != null) {" + " for (var i = 0; i < x.files.length; i++) { " " var f = x.files[i];" - " if(f.size < " + maxFileSize + ") \n" - " " + jsRef() + ".submit() \n" - " else \n" - " " + tooLarge_.createCall("f.size") + - " }};"; + " if(f.size < " + maxFileSize + ") { " + " " + jsRef() + ".submit(); " + " } else { " + " " + fileTooLarge().createCall("f.size") + + " }" + " }" + " } else " + " " + jsRef() + ".submit(); " + " };"; element.callJavaScript(command); flags_.reset(BIT_DO_UPLOAD); @@ -446,13 +443,21 @@ DomElement *WFileUpload::createDomElement(WApplication *app) form->addChild(input); - doJavaScript("window.addEventListener('message', function(event) {" + std::stringstream s; + + doJavaScript("var f = function(event) {" """if (" + jsRef() + ".action.indexOf(event.origin) === 0) {" - "" "if (event.data.fu == '" + id() + "')" + "" "var data = JSON.parse(event.data);" + "" "if (data.fu == '" + id() + "')" + app->javaScriptClass() - + "._p_.update(null, event.data.signal, null, true);" + + "._p_.update(null, data.signal, null, true);" """}" - "}, false);"); + "};" + "if (window.addEventListener) " + """window.addEventListener('message', f, false);" + "else " + """window.attachEvent('onmessage', f);" + ); } else { result->setAttribute("type", "file"); if (flags_.test(BIT_MULTIPLE)) diff --git a/test/dbo/DboTest.C b/test/dbo/DboTest.C index eddabd4293..1ca9b93663 100644 --- a/test/dbo/DboTest.C +++ b/test/dbo/DboTest.C @@ -2316,3 +2316,92 @@ BOOST_AUTO_TEST_CASE( dbo_test25 ) } #endif // FIREBIRD } + +BOOST_AUTO_TEST_CASE( dbo_test26 ) +{ +#ifndef SQLITE3 // sqlite3 ":memory:" does not share database between sessions + DboFixture f; + + dbo::Session *session_ = f.session_; + + struct CheckExpected : Wt::WObject { + DboFixture& f_; + dbo::Session *session2_; + + CheckExpected(DboFixture &f) : f_(f) { + session2_ = new dbo::Session(); + session2_->setConnectionPool(*f_.connectionPool_); + session2_->mapClass(SCHEMA "table_f"); + } + + virtual ~CheckExpected() { + delete session2_; + } + + bool operator() (std::string &expected) { + { + dbo::Transaction t2(*session2_); + dbo::ptr c = session2_->find(); + if (c->firstName != expected) + BOOST_ERROR(std::string("CheckExpected: firstName != expected, firstName: '") + + c->firstName + "', expected: '" + expected + "'"); + else + BOOST_TEST_MESSAGE(std::string("CheckExpected OK: firstName: '") + + c->firstName + "', expected: '" + expected + "'"); + } + return true; + } + } checkExpected(f); + + { + dbo::Transaction t(*session_); + + session_->add(new F("Alice", "Kramden", "Female")); + + dbo::Query< dbo::ptr > query = session_->find(); + dbo::QueryModel< dbo::ptr > *model + = new dbo::QueryModel< dbo::ptr >(); + + model->setQuery(query); + model->addAllFieldsAsColumns(); + + BOOST_REQUIRE(model->columnCount() == 5); + BOOST_REQUIRE(model->rowCount() == 1); + t.commit(); + + BOOST_REQUIRE(Wt::asString(model->data(0, 2)) == "Alice"); + + std::string ExpectedFirstName = "Alice"; + BOOST_REQUIRE(checkExpected(ExpectedFirstName)); + + /* + * Set-up a handler to verify that updates are visible + * in a second session when model->dataChanged() is emitted + */ + model->dataChanged().connect(boost::bind(boost::ref(checkExpected), + boost::ref(ExpectedFirstName))); + + /* + * The setItemData() convenience method commits + * a transaction prior to emitting dataChanged() + */ + ExpectedFirstName = "AliceTwo"; + Wt::WAbstractItemModel::DataMap map; + map[Wt::EditRole] = ExpectedFirstName; + model->setItemData(model->index(0, 2), map); // checkExpected() will be called + + BOOST_REQUIRE(Wt::asString(model->data(0, 2)) == ExpectedFirstName); + + /* + * The setData() should be equivalent to above setItemData() and + * commit a transaction prior to emitting dataChanged() + */ + ExpectedFirstName = "AliceThree"; + model->setData(0, 2, ExpectedFirstName); // checkExpected() will be called + + BOOST_REQUIRE(Wt::asString(model->data(0, 2)) == ExpectedFirstName); + + delete model; + } +#endif // SQLITE3 +}