// -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*- /* * Copyright (C) 2011 Canonical Ltd * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License version 3 as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Neil Jagdish Patel */ #ifndef UNITY_MODEL_INL_H #define UNITY_MODEL_INL_H #include namespace unity { namespace dash { template Model::Model (ModelType model_type) : model_type_(model_type) , cached_adaptor1_(nullptr, nullptr, nullptr) , cached_adaptor2_(nullptr, nullptr, nullptr) , cached_adaptor3_(nullptr, nullptr, nullptr) { Init(); if (model_type == ModelType::LOCAL) swarm_name = ":local"; } template void Model::Init () { swarm_name.changed.connect(sigc::mem_fun(this, &Model::OnSwarmNameChanged)); count.SetGetterFunction(std::bind(&Model::get_count, this)); seqnum.SetGetterFunction(std::bind(&Model::get_seqnum, this)); model.SetGetterFunction(std::bind(&Model::get_model, this)); } template void Model::OnSwarmNameChanged(std::string const& swarm_name) { static nux::logging::Logger local_logger("unity.dash.model"); LOG_DEBUG(local_logger) << "New swarm name: " << swarm_name; glib::Object new_model; switch(model_type_) { case ModelType::LOCAL: new_model = dee_sequence_model_new(); break; case ModelType::REMOTE: case ModelType::REMOTE_SHARED: new_model = dee_shared_model_new(swarm_name.c_str()); break; case ModelType::UNATTACHED: break; default: LOG_ERROR(local_logger) << "Unexpected ModelType " << model_type_; break; } SetModel(new_model); } template void Model::SetModel(glib::Object const& new_model) { GetDeeTagFunc func = [](glib::Object const& model) { return dee_model_register_tag(model, NULL); }; SetModel(new_model, func); } template void Model::SetModel(glib::Object const& new_model, GetDeeTagFunc const& get_dee_tag_func) { typedef glib::Signal TransactionSignalType; typedef glib::Signal RowSignalType; // Check if it's the same as the current model. if (new_model == model_) return; // Let the views clean up properly if (model_) { dee_model_clear(model_); sig_manager_.Disconnect(model_); model_.Release(); } model_ = new_model; if (!model_) return; switch(model_type_) { case ModelType::REMOTE_SHARED: sig_manager_.Add(new TransactionSignalType(model_, "begin-transaction", sigc::mem_fun(this, &Model::OnTransactionBegin))); sig_manager_.Add(new TransactionSignalType(model_, "end-transaction", sigc::mem_fun(this, &Model::OnTransactionEnd))); break; case ModelType::REMOTE: case ModelType::LOCAL: case ModelType::UNATTACHED: default: break; } renderer_tag_ = get_dee_tag_func(model_); sig_manager_.Add(new RowSignalType(model_, "row-added", sigc::mem_fun(this, &Model::OnRowAdded))); sig_manager_.Add(new RowSignalType(model_, "row-changed", sigc::mem_fun(this, &Model::OnRowChanged))); sig_manager_.Add(new RowSignalType(model_, "row-removed", sigc::mem_fun(this, &Model::OnRowRemoved))); model.EmitChanged(model_); // if the model wasn't empty emit row-added signals for all the rows DeeModelIter* iter = dee_model_get_first_iter(model_); DeeModelIter* end_iter = dee_model_get_last_iter(model_); while (iter != end_iter) { OnRowAdded(model_, iter); iter = dee_model_next(model_, iter); } } template Model::~Model() {} template void Model::OnRowAdded(DeeModel* model, DeeModelIter* iter) { // careful here - adding rows to the model inside the callback // will invalidate the cached_adaptor! // This needs to be used as a listener only! cached_adaptor1_.SetTarget(model, iter, renderer_tag_); row_added.emit(cached_adaptor1_); } template void Model::OnRowChanged(DeeModel* model, DeeModelIter* iter) { // careful here - changing rows inside the callback will invalidate // the cached_adaptor! // This needs to be used as a listener only! cached_adaptor2_.SetTarget(model, iter, renderer_tag_); row_changed.emit(cached_adaptor2_); } template void Model::OnRowRemoved(DeeModel* model, DeeModelIter* iter) { // careful here - removing rows from the model inside the callback // will invalidate the cached_adaptor! // This needs to be used as a listener only! cached_adaptor3_.SetTarget(model, iter, renderer_tag_); row_removed.emit(cached_adaptor3_); } template void Model::OnTransactionBegin(DeeModel* model, guint64 begin_seqnum64, guint64 end_seqnum64) { uint64_t begin_seqnum, end_seqnum; begin_seqnum = static_cast (begin_seqnum64); end_seqnum = static_cast (end_seqnum64); begin_transaction.emit(begin_seqnum, end_seqnum); } template void Model::OnTransactionEnd(DeeModel* model, guint64 begin_seqnum64, guint64 end_seqnum64) { uint64_t begin_seqnum, end_seqnum; begin_seqnum = static_cast (begin_seqnum64); end_seqnum = static_cast (end_seqnum64); end_transaction.emit(begin_seqnum, end_seqnum); } template const RowAdaptor Model::RowAtIndex(std::size_t index) const { RowAdaptor it(model_, dee_model_get_iter_at_row(model_, index), renderer_tag_); return it; } template DeeModelTag* Model::GetTag() const { return renderer_tag_; } template std::size_t Model::get_count() const { if (model_) return dee_model_get_n_rows(model_); else return 0; } template uint64_t Model::get_seqnum() const { if (model_ && DEE_IS_SERIALIZABLE_MODEL ((DeeModel*) model_)) return dee_serializable_model_get_seqnum(model_); else return 0; } template glib::Object Model::get_model() const { return model_; } } } #endif