Back to index

unity  6.0.0
MultiRangeFilter.cpp
Go to the documentation of this file.
00001 // -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*-
00002 /*
00003  * Copyright (C) 2011 Canonical Ltd
00004  *
00005  * This program is free software: you can redistribute it and/or modify
00006  * it under the terms of the GNU General Public License version 3 as
00007  * published by the Free Software Foundation.
00008  *
00009  * This program is distributed in the hope that it will be useful,
00010  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012  * GNU General Public License for more details.
00013  *
00014  * You should have received a copy of the GNU General Public License
00015  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
00016  *
00017  * Authored by: Neil Jagdish Patel <neil.patel@canonical.com>
00018  */
00019 
00020 #include "MultiRangeFilter.h"
00021 
00022 #include <NuxCore/Logger.h>
00023 
00024 namespace unity
00025 {
00026 namespace dash
00027 {
00028 
00029 namespace
00030 {
00031 nux::logging::Logger logger("unity.dash.multirangefilter");
00032 }
00033 
00034 MultiRangeFilter::MultiRangeFilter(DeeModel* model, DeeModelIter* iter)
00035   : Filter(model, iter)
00036   , left_pos_(-1)
00037   , right_pos_(-1)
00038   , ignore_changes_(false)
00039 {
00040   options.SetGetterFunction(sigc::mem_fun(this, &MultiRangeFilter::get_options));
00041   Refresh();
00042 }
00043 
00044 void MultiRangeFilter::Clear()
00045 {
00046   left_pos_ = -1;
00047   right_pos_ = -1;
00048 
00049   ignore_changes_ = true;
00050   
00051   for(auto option: options_)
00052     option->active = false;
00053 
00054   ignore_changes_ = false;
00055 
00056   UpdateState();
00057 }
00058 
00059 void MultiRangeFilter::Update(Filter::Hints& hints)
00060 {
00061   GVariant* options_variant = hints["options"];
00062   GVariantIter* options_iter;
00063 
00064   g_variant_get(options_variant, "a(sssb)", &options_iter);
00065 
00066   char *id = NULL;
00067   char *name = NULL;
00068   char *icon_hint = NULL;
00069   gboolean active = false;
00070 
00071   for (auto option: options_)
00072     option_removed.emit(option);
00073 
00074   options_.clear();
00075 
00076   while (g_variant_iter_loop(options_iter, "(sssb)", &id, &name, &icon_hint, &active))
00077   {
00078     FilterOption::Ptr option(new FilterOption(id, name, icon_hint, active));
00079 
00080     std::string data(id);
00081     option->active.changed.connect(sigc::bind(sigc::mem_fun(this, &MultiRangeFilter::OptionChanged), data));
00082     options_.push_back(option);
00083     option_added.emit(option);
00084   }
00085 
00086   g_variant_iter_free(options_iter);
00087 }
00088 
00089 void MultiRangeFilter::OptionChanged(bool is_active, std::string const& id)
00090 {
00091   if (ignore_changes_)
00092     return;
00093 
00094   int position = PositionOfId(id);
00095 
00096   if (is_active)
00097   {
00098     if (left_pos_ == -1 && right_pos_ == -1)
00099     {
00100       left_pos_ = position;
00101       right_pos_ = position;
00102     }
00103     else if (left_pos_ > position)
00104     {
00105       left_pos_ = position;
00106     }
00107     else if (right_pos_ < position)
00108     {
00109       right_pos_ = position;
00110     }
00111   }
00112   else
00113   {
00114     // Reset if the one and only block is deactivated
00115     if (position == right_pos_ && position == left_pos_)
00116     {
00117       left_pos_ = -1;
00118       right_pos_ = -1;
00119     }
00120     // If the deactivated block is on either end, remove it
00121     else if (position == right_pos_)
00122     {
00123       right_pos_ = position - 1;
00124     }
00125     else if (position == left_pos_)
00126     {
00127       left_pos_ = position + 1;
00128     }
00129     // It's in the middle of the range, see which side to shorten
00130     else if (position < (left_pos_ + ((right_pos_ - left_pos_)/2.0f)))
00131     {
00132       left_pos_ = position;
00133     }
00134     else
00135     {
00136       right_pos_ = position;
00137     }
00138   }
00139 
00140   ignore_changes_ = true;
00141   int i = 0;
00142   for(auto option: options_)
00143   {
00144     if (i < left_pos_)
00145       option->active = false;
00146     else if (i <= right_pos_)
00147       option->active = true;
00148     else
00149       option->active = false;
00150 
00151     i++;
00152   }
00153   ignore_changes_ = false;
00154 
00155   UpdateState();
00156 }
00157 
00158 MultiRangeFilter::Options const& MultiRangeFilter::get_options() const
00159 {
00160   return options_;
00161 }
00162 
00163 void MultiRangeFilter::UpdateState()
00164 {
00165   if (!IsValid())
00166     return;
00167   gboolean raw_filtering = FALSE;
00168 
00169   GVariantBuilder options;
00170   g_variant_builder_init(&options, G_VARIANT_TYPE("a(sssb)"));
00171 
00172   for(auto option: options_)
00173   {
00174     std::string id = option->id;
00175     std::string name = option->name;
00176     std::string icon_hint = option->icon_hint;
00177     bool active = option->active;
00178 
00179     raw_filtering = raw_filtering ? TRUE : active;
00180 
00181     g_variant_builder_add(&options, "(sssb)",
00182                           id.c_str(), name.c_str(),
00183                           icon_hint.c_str(), active ? TRUE : FALSE);
00184   }
00185   
00186   GVariantBuilder hints;
00187   g_variant_builder_init(&hints, G_VARIANT_TYPE("a{sv}"));
00188   g_variant_builder_add(&hints, "{sv}", "options", g_variant_builder_end(&options));
00189 
00190   IgnoreChanges(true);
00191   dee_model_set_value(model_,iter_,
00192                       FilterColumn::RENDERER_STATE,
00193                       g_variant_builder_end(&hints));
00194   dee_model_set_value(model_, iter_,
00195                       FilterColumn::FILTERING,
00196                       g_variant_new("b", raw_filtering));
00197   IgnoreChanges(false);
00198 
00199   filtering.EmitChanged(filtering);
00200 }
00201 
00202 int MultiRangeFilter::PositionOfId(std::string const& id)
00203 {
00204   int i = 0;
00205   for (auto option: options_)
00206   {
00207     if (option->id == id)
00208       return i;
00209     i++;
00210   }
00211   return -1;
00212 }
00213 
00214 
00215 }
00216 }