// -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*- /* * Copyright (C) 2010-2012 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 * Marco Trevisan */ #include #include #include #include "FavoriteStoreGSettings.h" #include "FavoriteStorePrivate.h" #include "config.h" /** * Internally the favorite store keeps the full path to the application, but * when saving, only the desktop file id is saved if the favorite is in one of * the system directories. If the favorite isn't in one of the system * directories, the full path is saved in the settings. */ namespace unity { namespace internal { DECLARE_LOGGER(logger, "unity.favorite.store.gsettings"); namespace { const std::string SETTINGS_NAME = "com.canonical.Unity.Launcher"; const std::string SETTINGS_KEY = "favorites"; } FavoriteStoreGSettings::FavoriteStoreGSettings() : ignore_signals_(false) , settings_(g_settings_new(SETTINGS_NAME.c_str())) { favorites_changed_.Connect(settings_, "changed::"+SETTINGS_KEY, [this] (GSettings*, gchar*) { Changed(); }); Refresh(); } void FavoriteStoreGSettings::Refresh() { FillList(); } void FavoriteStoreGSettings::FillList() { favorites_.clear(); std::unique_ptr favs(g_settings_get_strv(settings_, SETTINGS_KEY.c_str()), g_strfreev); for (int i = 0; favs[i]; ++i) { std::string const& fav = ParseFavoriteFromUri(favs[i]); if (!fav.empty()) favorites_.push_back(fav); } } FavoriteList const& FavoriteStoreGSettings::GetFavorites() const { return favorites_; } void FavoriteStoreGSettings::AddFavorite(std::string const& icon_uri, int position) { std::string const& fav = ParseFavoriteFromUri(icon_uri); if (fav.empty() || position > static_cast(favorites_.size())) return; if (position < 0) { // It goes on the end. favorites_.push_back(fav); } else { FavoriteList::iterator pos = favorites_.begin(); std::advance(pos, position); favorites_.insert(pos, fav); } SaveFavorites(favorites_); Refresh(); } void FavoriteStoreGSettings::RemoveFavorite(std::string const& icon_uri) { std::string const& fav = ParseFavoriteFromUri(icon_uri); if (fav.empty()) return; FavoriteList::iterator pos = std::find(favorites_.begin(), favorites_.end(), fav); if (pos == favorites_.end()) return; favorites_.erase(pos); SaveFavorites(favorites_); Refresh(); } void FavoriteStoreGSettings::MoveFavorite(std::string const& icon_uri, int position) { std::string const& fav = ParseFavoriteFromUri(icon_uri); if (fav.empty() || position > static_cast(favorites_.size())) return; FavoriteList::iterator pos = std::find(favorites_.begin(), favorites_.end(), fav); if (pos == favorites_.end()) return; favorites_.erase(pos); if (position < 0) { // It goes on the end. favorites_.push_back(fav); } else { FavoriteList::iterator insert_pos = favorites_.begin(); std::advance(insert_pos, position); favorites_.insert(insert_pos, fav); } SaveFavorites(favorites_); Refresh(); } void FavoriteStoreGSettings::SetFavorites(FavoriteList const& favorites) { SaveFavorites(favorites); Refresh(); } void FavoriteStoreGSettings::SaveFavorites(FavoriteList const& favorites, bool ignore) { const int size = favorites.size(); const char* favs[size + 1]; // Since we don't always save the full path, we store the values we are // actually going to save in a different list. FavoriteList values; int index = 0; for (auto const& fav_uri : favorites) { std::string const& fav = ParseFavoriteFromUri(fav_uri); if (fav.empty()) { LOG_WARNING(logger) << "Impossible to add favorite '" << fav_uri << "' to store"; continue; } // By using insert we get the iterator to the newly inserted string value. // That way we can use the c_str() method to access the const char* for // the string that we are going to save. This way we know that the pointer // is valid for the lifetime of the favs array usage in the method call to // set the settings, and that we aren't referencing a temporary. FavoriteList::iterator iter = values.insert(values.end(), fav); favs[index] = iter->c_str(); ++index; } for (int i = index; i <= size; ++i) favs[i] = nullptr; ignore_signals_ = ignore; if (!g_settings_set_strv(settings_, SETTINGS_KEY.c_str(), favs)) { LOG_WARNING(logger) << "Saving favorites failed."; } ignore_signals_ = false; } void FavoriteStoreGSettings::Changed() { if (ignore_signals_) return; FavoriteList old(favorites_); FillList(); auto newbies = impl::GetNewbies(old, favorites_); for (auto it : favorites_) { if (std::find(newbies.begin(), newbies.end(), it) == newbies.end()) continue; std::string pos; bool before; impl::GetSignalAddedInfo(favorites_, newbies , it, pos, before); favorite_added.emit(it, pos, before); } for (auto it : impl::GetRemoved(old, favorites_)) { favorite_removed.emit(it); } if (impl::NeedToBeReordered(old, favorites_)) reordered.emit(); } bool FavoriteStoreGSettings::IsFavorite(std::string const& icon_uri) const { return std::find(favorites_.begin(), favorites_.end(), icon_uri) != favorites_.end(); } int FavoriteStoreGSettings::FavoritePosition(std::string const& icon_uri) const { int index = 0; for (auto const& fav : favorites_) { if (fav == icon_uri) return index; ++index; } return -1; } } // namespace internal } // namespace unity