1// Copyright (c) 2011 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 "chrome/browser/tabs/tab_strip_selection_model.h"
6
7#include <algorithm>
8#include <valarray>
9
10#include "base/logging.h"
11
12// static
13const int TabStripSelectionModel::kUnselectedIndex = -1;
14
15static void IncrementFromImpl(int index, int* value) {
16  if (*value >= index)
17    (*value)++;
18}
19
20static bool DecrementFromImpl(int index, int* value) {
21  if (*value == index) {
22    *value = TabStripSelectionModel::kUnselectedIndex;
23    return true;
24  }
25  if (*value > index)
26    (*value)--;
27  return false;
28}
29
30TabStripSelectionModel::TabStripSelectionModel()
31    : active_(kUnselectedIndex),
32      anchor_(kUnselectedIndex) {
33}
34
35TabStripSelectionModel::~TabStripSelectionModel() {
36}
37
38void TabStripSelectionModel::IncrementFrom(int index) {
39  // Shift the selection to account for the newly inserted tab.
40  for (SelectedIndices::iterator i = selected_indices_.begin();
41       i != selected_indices_.end(); ++i) {
42    IncrementFromImpl(index, &(*i));
43  }
44  IncrementFromImpl(index, &anchor_);
45  IncrementFromImpl(index, &active_);
46}
47
48void TabStripSelectionModel::DecrementFrom(int index) {
49  for (SelectedIndices::iterator i = selected_indices_.begin();
50       i != selected_indices_.end(); ) {
51    if (DecrementFromImpl(index, &(*i)))
52      i = selected_indices_.erase(i);
53    else
54      ++i;
55  }
56  DecrementFromImpl(index, &anchor_);
57  DecrementFromImpl(index, &active_);
58}
59
60void TabStripSelectionModel::SetSelectedIndex(int index) {
61  anchor_ = active_ = index;
62  SetSelectionFromAnchorTo(index);
63}
64
65bool TabStripSelectionModel::IsSelected(int index) const {
66  return std::find(selected_indices_.begin(), selected_indices_.end(), index) !=
67      selected_indices_.end();
68}
69
70void TabStripSelectionModel::AddIndexToSelection(int index) {
71  if (!IsSelected(index)) {
72    selected_indices_.push_back(index);
73    std::sort(selected_indices_.begin(), selected_indices_.end());
74  }
75}
76
77void TabStripSelectionModel::RemoveIndexFromSelection(int index) {
78  SelectedIndices::iterator i = std::find(selected_indices_.begin(),
79                                          selected_indices_.end(), index);
80  if (i != selected_indices_.end())
81    selected_indices_.erase(i);
82}
83
84void TabStripSelectionModel::SetSelectionFromAnchorTo(int index) {
85  if (anchor_ == kUnselectedIndex) {
86    SetSelectedIndex(index);
87  } else {
88    int delta = std::abs(index - anchor_);
89    SelectedIndices new_selection(delta + 1, 0);
90    for (int i = 0, min = std::min(index, anchor_); i <= delta; ++i)
91      new_selection[i] = i + min;
92    selected_indices_.swap(new_selection);
93    active_ = index;
94  }
95}
96
97void TabStripSelectionModel::AddSelectionFromAnchorTo(int index) {
98  if (anchor_ == kUnselectedIndex) {
99    SetSelectedIndex(index);
100  } else {
101    for (int i = std::min(index, anchor_), end = std::max(index, anchor_);
102         i <= end; ++i) {
103      if (!IsSelected(i))
104        selected_indices_.push_back(i);
105    }
106    std::sort(selected_indices_.begin(), selected_indices_.end());
107    active_ = index;
108  }
109}
110
111void TabStripSelectionModel::Move(int from, int to) {
112  DCHECK_NE(to, from);
113  bool was_anchor = from == anchor_;
114  bool was_active = from == active_;
115  bool was_selected = IsSelected(from);
116  if (to < from) {
117    IncrementFrom(to);
118    DecrementFrom(from + 1);
119  } else {
120    DecrementFrom(from);
121    IncrementFrom(to);
122  }
123  if (was_active)
124    active_ = to;
125  if (was_anchor)
126    anchor_ = to;
127  if (was_selected)
128    AddIndexToSelection(to);
129}
130
131void TabStripSelectionModel::Clear() {
132  anchor_ = active_ = kUnselectedIndex;
133  SelectedIndices empty_selection;
134  selected_indices_.swap(empty_selection);
135}
136
137void TabStripSelectionModel::Copy(const TabStripSelectionModel& source) {
138  selected_indices_ = source.selected_indices_;
139  active_ = source.active_;
140  anchor_ = source.anchor_;
141}
142