Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(433)

Side by Side Diff: chrome/browser/ui/views/tabs/base_tab_strip.cc

Issue 6579050: Elides the beginning of tab titles that have common prefixes. ... (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src/
Patch Set: '' Created 9 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "chrome/browser/ui/views/tabs/base_tab_strip.h" 5 #include "chrome/browser/ui/views/tabs/base_tab_strip.h"
6 6
7 #include <vector>
8
9 #include "base/command_line.h"
10 #include "base/hash_tables.h"
7 #include "base/logging.h" 11 #include "base/logging.h"
12 #include "base/string_split.h"
8 #include "chrome/browser/ui/view_ids.h" 13 #include "chrome/browser/ui/view_ids.h"
9 #include "chrome/browser/ui/views/tabs/dragged_tab_controller.h" 14 #include "chrome/browser/ui/views/tabs/dragged_tab_controller.h"
10 #include "chrome/browser/ui/views/tabs/tab_strip_controller.h" 15 #include "chrome/browser/ui/views/tabs/tab_strip_controller.h"
16 #include "chrome/common/chrome_switches.h"
11 #include "views/widget/root_view.h" 17 #include "views/widget/root_view.h"
12 #include "views/window/window.h" 18 #include "views/window/window.h"
13 19
14 #if defined(OS_WIN) 20 #if defined(OS_WIN)
15 #include "views/widget/widget_win.h" 21 #include "views/widget/widget_win.h"
16 #endif 22 #endif
17 23
18 namespace { 24 namespace {
19 25
20 // Animation delegate used when a dragged tab is released. When done sets the 26 // Animation delegate used when a dragged tab is released. When done sets the
(...skipping 117 matching lines...) Expand 10 before | Expand all | Expand 10 after
138 } 144 }
139 145
140 void BaseTabStrip::AddTabAt(int model_index, 146 void BaseTabStrip::AddTabAt(int model_index,
141 bool foreground, 147 bool foreground,
142 const TabRendererData& data) { 148 const TabRendererData& data) {
143 BaseTab* tab = CreateTab(); 149 BaseTab* tab = CreateTab();
144 tab->SetData(data); 150 tab->SetData(data);
145 151
146 TabData d = { tab, gfx::Rect() }; 152 TabData d = { tab, gfx::Rect() };
147 tab_data_.insert(tab_data_.begin() + ModelIndexToTabIndex(model_index), d); 153 tab_data_.insert(tab_data_.begin() + ModelIndexToTabIndex(model_index), d);
154 UpdateCommonTitlePrefix();
148 155
149 AddChildView(tab); 156 AddChildView(tab);
150 157
151 // Don't animate the first tab, it looks weird, and don't animate anything 158 // Don't animate the first tab, it looks weird, and don't animate anything
152 // if the containing window isn't visible yet. 159 // if the containing window isn't visible yet.
153 if (tab_count() > 1 && GetWindow() && GetWindow()->IsVisible()) 160 if (tab_count() > 1 && GetWindow() && GetWindow()->IsVisible())
154 StartInsertTabAnimation(model_index, foreground); 161 StartInsertTabAnimation(model_index, foreground);
155 else 162 else
156 DoLayout(); 163 DoLayout();
157 } 164 }
(...skipping 10 matching lines...) Expand all
168 175
169 tab_data_.insert(tab_data_.begin() + to_tab_data_index, data); 176 tab_data_.insert(tab_data_.begin() + to_tab_data_index, data);
170 177
171 StartMoveTabAnimation(); 178 StartMoveTabAnimation();
172 } 179 }
173 180
174 void BaseTabStrip::SetTabData(int model_index, const TabRendererData& data) { 181 void BaseTabStrip::SetTabData(int model_index, const TabRendererData& data) {
175 BaseTab* tab = GetBaseTabAtModelIndex(model_index); 182 BaseTab* tab = GetBaseTabAtModelIndex(model_index);
176 bool mini_state_changed = tab->data().mini != data.mini; 183 bool mini_state_changed = tab->data().mini != data.mini;
177 tab->SetData(data); 184 tab->SetData(data);
185 UpdateCommonTitlePrefix();
178 tab->SchedulePaint(); 186 tab->SchedulePaint();
179 187
180 if (mini_state_changed) { 188 if (mini_state_changed) {
181 if (GetWindow() && GetWindow()->IsVisible()) 189 if (GetWindow() && GetWindow()->IsVisible())
182 StartMiniTabAnimation(); 190 StartMiniTabAnimation();
183 else 191 else
184 DoLayout(); 192 DoLayout();
185 } 193 }
186 } 194 }
187 195
(...skipping 209 matching lines...) Expand 10 before | Expand all | Expand 10 after
397 405
398 void BaseTabStrip::RemoveAndDeleteTab(BaseTab* tab) { 406 void BaseTabStrip::RemoveAndDeleteTab(BaseTab* tab) {
399 int tab_data_index = TabIndexOfTab(tab); 407 int tab_data_index = TabIndexOfTab(tab);
400 408
401 DCHECK(tab_data_index != -1); 409 DCHECK(tab_data_index != -1);
402 410
403 // Remove the Tab from the TabStrip's list... 411 // Remove the Tab from the TabStrip's list...
404 tab_data_.erase(tab_data_.begin() + tab_data_index); 412 tab_data_.erase(tab_data_.begin() + tab_data_index);
405 413
406 delete tab; 414 delete tab;
415 UpdateCommonTitlePrefix();
416 }
417
418 void BaseTabStrip::UpdateCommonTitlePrefix() {
419 // Hidden behind a command line flag until we want to enable it always.
420 if (!CommandLine::ForCurrentProcess()->HasSwitch(
421 switches::kElideTabTitlePrefix)) {
422 return;
423 }
424
425 // First, we need to identify if there are identical titles,
426 // because we don't want to remove prefixes for those at all.
427 // We do it as a separate pass so that we don't need to remove
428 // previously parsed titles when we find a duplicate title later on.
429 // This set will contain the indexes of the tab that have a duplicate.
430 base::hash_set<int> no_prefix_tab;
431 // This map is used to remember the title and the index of a tab. If
432 // multiple tabs have the same title the index is set to -1 and the indices
433 // of all tabs sharing the same title are placed in no_prefix_tab.
434 base::hash_map<string16, int> existing_title;
435 for (int tab_index = 0; tab_index < tab_count(); ++tab_index) {
436 DCHECK(tab_data_[tab_index].tab != NULL);
437 if (tab_data_[tab_index].tab->data().mini ||
438 tab_data_[tab_index].tab->data().title.empty()) {
439 continue;
440 }
441 // We use pairs to test existence and insert in one shot.
442 std::pair<base::hash_map<string16, int>::iterator, bool> insert_result =
443 existing_title.insert(
444 std::make_pair(tab_data_[tab_index].tab->data().title, tab_index));
445 if (!insert_result.second) {
446 // We found a duplicate title, insert_result.second is false when we
447 // insert a duplicate in the set. insert_result.first is a map iterator
448 // and thus insert_result.first->first is the title key of the map.
449 DCHECK(tab_data_[tab_index].tab->data().title ==
450 insert_result.first->first);
451 no_prefix_tab.insert(tab_index);
452 // insert_result.first->second is the value of the tab index.
453 if (insert_result.first->second != -1) {
454 no_prefix_tab.insert(insert_result.first->second);
455 insert_result.first->second = -1;
456 }
457 }
458 }
459
460 // This next loop accumulates all the potential prefixes,
461 // and remember on which tabs we saw them.
462 base::hash_map<string16, std::vector<int> > prefixes;
463 for (int tab_index = 0; tab_index < tab_count(); ++tab_index) {
464 const TabRendererData& tab_data = tab_data_[tab_index].tab->data();
465 // Mini, title-less, and duplicate title tabs
466 // are not to be included in this process.
467 if (tab_data.mini || tab_data.title.empty() ||
468 no_prefix_tab.find(tab_index) != no_prefix_tab.end()) {
469 continue;
470 }
471
472 // We only create prefixes at word boundaries.
473 std::vector<string16> words;
474 base::SplitStringAlongWhitespace(tab_data.title, &words);
475 if (words.size() > 1) {
476 size_t end_of_word = 0;
477 // We stop this for loop at words.size() - 1 because we don't need to
478 // insert the concatenation of all the words in the prefixes map because
479 // we ignore the complete title matches anyway.
480 for (size_t word_index = 0; word_index < words.size() - 1; ++word_index) {
481 if (!words[word_index].empty()) {
482 end_of_word = tab_data.title.find(words[word_index], end_of_word) +
483 words[word_index].size();
484 prefixes[tab_data.title.substr(0, end_of_word)].push_back(tab_index);
485 }
486 }
487 }
488 }
489
490 // Now we parse the map to find common prefixes and set the largest per tab.
491 std::vector<size_t> prefix_lengths(tab_count(), 0);
492 for (base::hash_map<string16, std::vector<int> >::iterator iter =
493 prefixes.begin(); iter != prefixes.end(); ++iter) {
494 if (iter->second.size() > 1) { // Need more than one with same prefix.
495 size_t prefix_length = iter->first.size();
496 for (size_t index = 0; index < iter->second.size(); ++index){
497 if (prefix_lengths[iter->second[index]] < prefix_length) {
498 prefix_lengths[iter->second[index]] = prefix_length;
499 }
500 }
501 }
502 }
503
504 // And finally, reset the tab data for the tabs that changed.
505 for (int tab_index = 0; tab_index < tab_count(); ++tab_index) {
506 TabRendererData data = tab_data_[tab_index].tab->data();
507 if (data.common_prefix_length != prefix_lengths[tab_index]) {
508 data.common_prefix_length = prefix_lengths[tab_index];
509 tab_data_[tab_index].tab->SetData(data);
510 }
511 }
407 } 512 }
408 513
409 int BaseTabStrip::TabIndexOfTab(BaseTab* tab) const { 514 int BaseTabStrip::TabIndexOfTab(BaseTab* tab) const {
410 for (int i = 0; i < tab_count(); ++i) { 515 for (int i = 0; i < tab_count(); ++i) {
411 if (base_tab_at_tab_index(i) == tab) 516 if (base_tab_at_tab_index(i) == tab)
412 return i; 517 return i;
413 } 518 }
414 return -1; 519 return -1;
415 } 520 }
416 521
(...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after
488 593
489 StopAnimating(false); 594 StopAnimating(false);
490 595
491 GenerateIdealBounds(); 596 GenerateIdealBounds();
492 597
493 for (int i = 0; i < tab_count(); ++i) 598 for (int i = 0; i < tab_count(); ++i)
494 tab_data_[i].tab->SetBoundsRect(tab_data_[i].ideal_bounds); 599 tab_data_[i].tab->SetBoundsRect(tab_data_[i].ideal_bounds);
495 600
496 SchedulePaint(); 601 SchedulePaint();
497 } 602 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698