Home | History | Annotate | Download | only in launcher
      1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "ash/launcher/launcher_model.h"
      6 
      7 #include <algorithm>
      8 
      9 #include "ash/ash_switches.h"
     10 #include "ash/launcher/launcher_model_observer.h"
     11 
     12 namespace ash {
     13 
     14 namespace {
     15 
     16 int LauncherItemTypeToWeight(LauncherItemType type) {
     17   if (ash::switches::UseAlternateShelfLayout()) {
     18     switch (type) {
     19       case TYPE_APP_LIST:
     20         return 0;
     21       case TYPE_BROWSER_SHORTCUT:
     22       case TYPE_APP_SHORTCUT:
     23       case TYPE_WINDOWED_APP:
     24         return 1;
     25       case TYPE_TABBED:
     26       case TYPE_PLATFORM_APP:
     27         return 2;
     28       case TYPE_APP_PANEL:
     29         return 3;
     30     }
     31   } else {
     32     switch (type) {
     33       case TYPE_BROWSER_SHORTCUT:
     34       case TYPE_APP_SHORTCUT:
     35       case TYPE_WINDOWED_APP:
     36         return 0;
     37       case TYPE_TABBED:
     38       case TYPE_PLATFORM_APP:
     39         return 1;
     40       case TYPE_APP_LIST:
     41         return 2;
     42       case TYPE_APP_PANEL:
     43         return 3;
     44     }
     45   }
     46 
     47   NOTREACHED() << "Invalid type " << type;
     48   return 1;
     49 }
     50 
     51 bool CompareByWeight(const LauncherItem& a, const LauncherItem& b) {
     52   return LauncherItemTypeToWeight(a.type) < LauncherItemTypeToWeight(b.type);
     53 }
     54 
     55 }  // namespace
     56 
     57 LauncherModel::LauncherModel() : next_id_(1), status_(STATUS_NORMAL) {
     58   LauncherItem app_list;
     59   app_list.type = TYPE_APP_LIST;
     60   app_list.is_incognito = false;
     61   AddAt(0, app_list);
     62 }
     63 
     64 LauncherModel::~LauncherModel() {
     65 }
     66 
     67 int LauncherModel::Add(const LauncherItem& item) {
     68   return AddAt(items_.size(), item);
     69 }
     70 
     71 int LauncherModel::AddAt(int index, const LauncherItem& item) {
     72   index = ValidateInsertionIndex(item.type, index);
     73   items_.insert(items_.begin() + index, item);
     74   items_[index].id = next_id_++;
     75   FOR_EACH_OBSERVER(LauncherModelObserver, observers_,
     76                     LauncherItemAdded(index));
     77   return index;
     78 }
     79 
     80 void LauncherModel::RemoveItemAt(int index) {
     81   DCHECK(index >= 0 && index < item_count());
     82   // The app list and browser shortcut can't be removed.
     83   DCHECK(items_[index].type != TYPE_APP_LIST &&
     84          items_[index].type != TYPE_BROWSER_SHORTCUT);
     85   LauncherID id = items_[index].id;
     86   items_.erase(items_.begin() + index);
     87   FOR_EACH_OBSERVER(LauncherModelObserver, observers_,
     88                     LauncherItemRemoved(index, id));
     89 }
     90 
     91 void LauncherModel::Move(int index, int target_index) {
     92   if (index == target_index)
     93     return;
     94   // TODO: this needs to enforce valid ranges.
     95   LauncherItem item(items_[index]);
     96   items_.erase(items_.begin() + index);
     97   items_.insert(items_.begin() + target_index, item);
     98   FOR_EACH_OBSERVER(LauncherModelObserver, observers_,
     99                     LauncherItemMoved(index, target_index));
    100 }
    101 
    102 void LauncherModel::Set(int index, const LauncherItem& item) {
    103   DCHECK(index >= 0 && index < item_count());
    104   int new_index = item.type == items_[index].type ?
    105       index : ValidateInsertionIndex(item.type, index);
    106 
    107   LauncherItem old_item(items_[index]);
    108   items_[index] = item;
    109   items_[index].id = old_item.id;
    110   FOR_EACH_OBSERVER(LauncherModelObserver, observers_,
    111                     LauncherItemChanged(index, old_item));
    112 
    113   // If the type changes confirm that the item is still in the right order.
    114   if (new_index != index) {
    115     // The move function works by removing one item and then inserting it at the
    116     // new location. However - by removing the item first the order will change
    117     // so that our target index needs to be corrected.
    118     // TODO(skuhne): Moving this into the Move function breaks lots of unit
    119     // tests. So several functions were already using this incorrectly.
    120     // That needs to be cleaned up.
    121     if (index < new_index)
    122       new_index--;
    123 
    124     Move(index, new_index);
    125   }
    126 }
    127 
    128 int LauncherModel::ItemIndexByID(LauncherID id) const {
    129   LauncherItems::const_iterator i = ItemByID(id);
    130   return i == items_.end() ? -1 : static_cast<int>(i - items_.begin());
    131 }
    132 
    133 LauncherItems::const_iterator LauncherModel::ItemByID(int id) const {
    134   for (LauncherItems::const_iterator i = items_.begin();
    135        i != items_.end(); ++i) {
    136     if (i->id == id)
    137       return i;
    138   }
    139   return items_.end();
    140 }
    141 
    142 int LauncherModel::FirstPanelIndex() const {
    143   LauncherItem weight_dummy;
    144   weight_dummy.type = TYPE_APP_PANEL;
    145   return std::lower_bound(items_.begin(), items_.end(), weight_dummy,
    146                           CompareByWeight) - items_.begin();
    147 }
    148 
    149 void LauncherModel::SetStatus(Status status) {
    150   if (status_ == status)
    151     return;
    152 
    153   status_ = status;
    154   FOR_EACH_OBSERVER(LauncherModelObserver, observers_,
    155                     LauncherStatusChanged());
    156 }
    157 
    158 void LauncherModel::AddObserver(LauncherModelObserver* observer) {
    159   observers_.AddObserver(observer);
    160 }
    161 
    162 void LauncherModel::RemoveObserver(LauncherModelObserver* observer) {
    163   observers_.RemoveObserver(observer);
    164 }
    165 
    166 int LauncherModel::ValidateInsertionIndex(LauncherItemType type,
    167                                           int index) const {
    168   DCHECK(index >= 0 && index <= item_count() +
    169       (ash::switches::UseAlternateShelfLayout() ? 1 : 0));
    170 
    171   // Clamp |index| to the allowed range for the type as determined by |weight|.
    172   LauncherItem weight_dummy;
    173   weight_dummy.type = type;
    174   index = std::max(std::lower_bound(items_.begin(), items_.end(), weight_dummy,
    175                                     CompareByWeight) - items_.begin(),
    176                    static_cast<LauncherItems::difference_type>(index));
    177   index = std::min(std::upper_bound(items_.begin(), items_.end(), weight_dummy,
    178                                     CompareByWeight) - items_.begin(),
    179                    static_cast<LauncherItems::difference_type>(index));
    180 
    181   return index;
    182 }
    183 
    184 }  // namespace ash
    185