// -*- 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: Jason Smith * Marco Trevisan */ #include "LauncherModel.h" #include "AbstractLauncherIcon.h" #include namespace unity { namespace launcher { LauncherModel::LauncherModel() : selection_(0) {} std::string LauncherModel::GetName() const { return "LauncherModel"; } void LauncherModel::AddProperties(debug::IntrospectionData& introspection) { introspection .add("selection", selection_); } debug::Introspectable::IntrospectableList LauncherModel::GetIntrospectableChildren() { int order = 0; std::list children; for (auto const& icon : _inner) { if (!icon->removed) { icon->SetOrder(++order); children.push_back(icon.GetPointer()); } } return children; } bool LauncherModel::IconShouldShelf(AbstractLauncherIcon::Ptr const& icon) const { return icon->position() == AbstractLauncherIcon::Position::END; } bool LauncherModel::CompareIcons(AbstractLauncherIcon::Ptr const& first, AbstractLauncherIcon::Ptr const& second) { if (first->position() < second->position()) return true; else if (first->position() > second->position()) return false; return first->SortPriority() < second->SortPriority(); } void LauncherModel::PopulatePart(iterator begin, iterator end) { AbstractLauncherIcon::Ptr prev_icon; for (auto it = begin; it != end; ++it) { auto const& icon = *it; _inner.push_back(icon); if (prev_icon) { // Ensuring that the current icon has higher priority than previous one if (icon->SortPriority() < prev_icon->SortPriority()) { int new_priority = prev_icon->SortPriority() + 1; icon->SetSortPriority(new_priority); } } prev_icon = icon; } } bool LauncherModel::Populate() { Base copy = _inner; _inner.clear(); PopulatePart(main_begin(), main_end()); PopulatePart(shelf_begin(), shelf_end()); return copy.size() == _inner.size() && !std::equal(begin(), end(), copy.begin()); } void LauncherModel::AddIcon(AbstractLauncherIcon::Ptr const& icon) { if (!icon || std::find(begin(), end(), icon) != end()) return; if (IconShouldShelf(icon)) _inner_shelf.push_back(icon); else _inner_main.push_back(icon); Sort(); icon_added.emit(icon); icon->on_icon_removed_connection = icon->remove.connect(sigc::mem_fun(this, &LauncherModel::OnIconRemove)); } void LauncherModel::RemoveIcon(AbstractLauncherIcon::Ptr const& icon) { size_t size; _inner_shelf.erase(std::remove(_inner_shelf.begin(), _inner_shelf.end(), icon), _inner_shelf.end()); _inner_main.erase(std::remove(_inner_main.begin(), _inner_main.end(), icon), _inner_main.end()); size = _inner.size(); _inner.erase(std::remove(_inner.begin(), _inner.end(), icon), _inner.end()); if (size != _inner.size()) { icon_removed.emit(icon); } } void LauncherModel::OnIconRemove(AbstractLauncherIcon::Ptr const& icon) { icon->removed = true; timeouts_.AddTimeout(1000, [this, icon] { RemoveIcon(icon); return false; }); } void LauncherModel::Save() { saved.emit(); } void LauncherModel::Sort() { std::stable_sort(_inner_shelf.begin(), _inner_shelf.end(), &LauncherModel::CompareIcons); std::stable_sort(_inner_main.begin(), _inner_main.end(), &LauncherModel::CompareIcons); if (Populate()) order_changed.emit(); } bool LauncherModel::IconHasSister(AbstractLauncherIcon::Ptr const& icon) const { if (!icon) return false; auto const& container = IconShouldShelf(icon) ? _inner_shelf : _inner_main; for (auto const& icon_it : container) { if (icon_it != icon && icon_it->GetIconType() == icon->GetIconType()) return true; } return false; } void LauncherModel::ReorderAfter(AbstractLauncherIcon::Ptr const& icon, AbstractLauncherIcon::Ptr const& other) { if (icon == other || icon.IsNull() || other.IsNull()) return; if (icon->position() != other->position()) return; icon->SetSortPriority(other->SortPriority() + 1); for (auto it = std::next(std::find(begin(), end(), other)); it != end(); ++it) { auto const& icon_it = *it; if (icon_it == icon) continue; // Increasing the priority of the icons next to the other one int new_priority = icon_it->SortPriority() + 2; icon_it->SetSortPriority(new_priority); } Sort(); } void LauncherModel::ReorderBefore(AbstractLauncherIcon::Ptr const& icon, AbstractLauncherIcon::Ptr const& other, bool animate) { if (icon == other || icon.IsNull() || other.IsNull()) return; if (icon->position() != other->position()) return; bool found_target = false; bool center = false; for (auto const& icon_it : _inner) { if (icon_it == icon) { center = !center; continue; } int old_priority = icon_it->SortPriority(); int new_priority = old_priority + (found_target ? 1 : -1); // We need to reduce the priority of all the icons previous to 'other' if (icon_it != other && !found_target && other->SortPriority() == old_priority) new_priority -= 1; icon_it->SetSortPriority(new_priority); if (icon_it == other) { if (animate && center) icon_it->SaveCenter(); center = !center; new_priority += -1; icon->SetSortPriority(new_priority); if (animate && center) icon_it->SaveCenter(); found_target = true; } else { if (animate && center) icon_it->SaveCenter(); } } Sort(); } void LauncherModel::ReorderSmart(AbstractLauncherIcon::Ptr const& icon, AbstractLauncherIcon::Ptr const& other, bool animate) { if (icon == other || icon.IsNull() || other.IsNull()) return; if (icon->position() != other->position()) return; bool found_icon = false; bool found_target = false; bool center = false; for (auto const& icon_it : _inner) { if (icon_it == icon) { found_icon = true; center = !center; continue; } int old_priority = icon_it->SortPriority(); int new_priority = old_priority + (found_target ? 1 : -1); // We need to reduce the priority of all the icons previous to 'other' if (icon_it != other && !found_target && other->SortPriority() == old_priority) new_priority -= 1; icon_it->SetSortPriority(new_priority); if (icon_it == other) { if (animate && center) icon_it->SaveCenter(); center = !center; new_priority += found_icon ? 1 : -1; icon->SetSortPriority(new_priority); if (animate && center) icon_it->SaveCenter(); found_target = true; } else { if (animate && center) icon_it->SaveCenter(); } } Sort(); } int LauncherModel::Size() const { return _inner.size(); } AbstractLauncherIcon::Ptr const& LauncherModel::Selection() const { return _inner[selection_]; } int LauncherModel::SelectionIndex() const { return selection_; } void LauncherModel::SetSelection(int selection) { int new_selection = std::min(Size() - 1, std::max (0, selection)); if (new_selection == selection_) return; selection_ = new_selection; selection_changed.emit(Selection()); } void LauncherModel::SelectNext() { int temp = selection_; temp++; while (temp != selection_) { if (temp >= Size()) temp = 0; if (_inner[temp]->IsVisible()) { selection_ = temp; selection_changed.emit(Selection()); break; } temp++; } } void LauncherModel::SelectPrevious() { int temp = selection_; temp--; while (temp != selection_) { if (temp < 0) temp = Size() - 1; if (_inner[temp]->IsVisible()) { selection_ = temp; selection_changed.emit(Selection()); break; } temp--; } } AbstractLauncherIcon::Ptr LauncherModel::GetClosestIcon(AbstractLauncherIcon::Ptr const& icon, bool& is_before) const { AbstractLauncherIcon::Ptr prev, next; bool found_target = false; for (auto const& current : _inner) { if (current->position() != icon->position()) continue; if (!found_target) { if (current == icon) { found_target = true; if (prev) break; } else { prev = current; } } else { next = current; break; } } is_before = next.IsNull(); return is_before ? prev : next; } int LauncherModel::IconIndex(AbstractLauncherIcon::Ptr const& target) const { int pos = 0; bool found = false; for (auto const& icon : _inner) { if (icon == target) { found = true; break; } ++pos; } return found ? pos : -1; } /* iterators */ LauncherModel::iterator LauncherModel::begin() { return _inner.begin(); } LauncherModel::iterator LauncherModel::end() { return _inner.end(); } LauncherModel::iterator LauncherModel::at(int index) { LauncherModel::iterator it; int i; // start currently selected icon for (it = _inner.begin(), i = 0; it != _inner.end(); ++it, i++) { if (i == index) return it; } return (LauncherModel::iterator)NULL; } LauncherModel::reverse_iterator LauncherModel::rbegin() { return _inner.rbegin(); } LauncherModel::reverse_iterator LauncherModel::rend() { return _inner.rend(); } LauncherModel::iterator LauncherModel::main_begin() { return _inner_main.begin(); } LauncherModel::iterator LauncherModel::main_end() { return _inner_main.end(); } LauncherModel::reverse_iterator LauncherModel::main_rbegin() { return _inner_main.rbegin(); } LauncherModel::reverse_iterator LauncherModel::main_rend() { return _inner_main.rend(); } LauncherModel::iterator LauncherModel::shelf_begin() { return _inner_shelf.begin(); } LauncherModel::iterator LauncherModel::shelf_end() { return _inner_shelf.end(); } LauncherModel::reverse_iterator LauncherModel::shelf_rbegin() { return _inner_shelf.rbegin(); } LauncherModel::reverse_iterator LauncherModel::shelf_rend() { return _inner_shelf.rend(); } } // namespace launcher } // namespace unity