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

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 existing title and the index of the
432 // tab we saw them in first, once we put this other index in the
sky 2011/02/25 17:02:07 This is a bit confusing. I think you mean: 'This m
MAD 2011/02/25 20:09:13 Thanks... Done...
433 // no_prefix_tab set, we set the index to -1.
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);
sky 2011/02/25 17:02:07 Shouldn't you skip over mini tabs?
MAD 2011/02/25 20:09:13 Good point, it would save some processing time sin
sky 2011/02/25 21:04:44 I wasn't so much concerned about that, but rather
MAD 2011/02/25 21:49:24 Yes, that too... :-) Fixed now, right?
sky 2011/02/25 22:59:27 Yes, thanks.
437 // We use pairs to test existence and insert in one shot.
438 std::pair<base::hash_map<string16, int>::iterator, bool> insert_result =
439 existing_title.insert(
440 std::make_pair(tab_data_[tab_index].tab->data().title, tab_index));
441 if (!insert_result.second) {
442 DCHECK(tab_data_[tab_index].tab->data().title ==
sky 2011/02/25 17:02:07 This code is tricky to read, how about a comment h
MAD 2011/02/25 20:09:13 Done...
443 insert_result.first->first);
444 no_prefix_tab.insert(tab_index);
445 if (insert_result.first->second != -1) {
446 no_prefix_tab.insert(insert_result.first->second);
447 insert_result.first->second = -1;
448 }
449 }
450 }
451
452 // This next loop accumulates all the potential prefixes,
453 // and remember on which tabs we saw them.
454 base::hash_map<string16, std::vector<size_t> > prefixes;
sky 2011/02/25 17:02:07 Shouldn't this be std::vector<int> ?
MAD 2011/02/25 20:09:13 Ho, right, thanks again... Done...
455 for (int tab_index = 0; tab_index < tab_count(); ++tab_index) {
456 const TabRendererData& tab_data = tab_data_[tab_index].tab->data();
457 // Mini, title-less, and duplicate title tabs
458 // are not to be included in this process.
459 if (tab_data.mini || tab_data.title.empty() ||
460 no_prefix_tab.find(tab_index) != no_prefix_tab.end()) {
461 continue;
462 }
463
464 // We only create prefixes at word boundaries.
465 std::vector<string16> words;
466 base::SplitStringAlongWhitespace(tab_data.title, &words);
Peter Kasting 2011/02/25 17:14:44 This is the wrong function to use. We need to use
MAD 2011/02/25 20:09:13 Will do in the next iteration, when I move the cod
467 size_t end_of_word = 0;
468 // We don't need the last word, since we ignored duplicate titles above.
sky 2011/02/25 17:02:07 Maybe I'm just dense, but this comment doesn't mak
MAD 2011/02/25 20:09:13 Sorry, maybe my wording is wrong (unintended pun :
469 for (size_t word_index = 0; word_index < words.size() - 1; ++word_index) {
sky 2011/02/25 17:02:07 If words is empty, this is never stops. This might
MAD 2011/02/25 20:09:13 Hum, I thought I did handle that case by exiting t
470 if (!words[word_index].empty()) {
471 end_of_word = tab_data.title.find(words[word_index], end_of_word) +
sky 2011/02/25 17:02:07 It seems horribly inefficient to have to use find
MAD 2011/02/25 20:09:13 Yeah, I know, I was debating whether I should just
472 words[word_index].size();
473 prefixes[tab_data.title.substr(0, end_of_word)].push_back(tab_index);
474 }
475 }
476 }
477
478 // Now we parse the map to find common prefixes and set the largest per tab.
479 std::vector<size_t> prefix_lengths(tab_count(), 0);
480 base::hash_map<string16, std::vector<size_t> >::iterator iter =
sky 2011/02/25 17:02:07 Move the iter into the for declaration so that its
MAD 2011/02/25 20:09:13 Done...
481 prefixes.begin();
482 for (; iter != prefixes.end(); ++iter) {
483 if (iter->second.size() > 1) { // Need more than one with same prefix.
484 size_t prefix_length = iter->first.size();
485 for (size_t index = 0; index < iter->second.size(); ++index){
486 if (prefix_lengths[iter->second[index]] < prefix_length) {
487 prefix_lengths[iter->second[index]] = prefix_length;
488 }
489 }
490 }
491 }
492
493 // And finally, reset the tab data for the tabs that changed.
494 for (int tab_index = 0; tab_index < tab_count(); ++tab_index) {
495 TabRendererData data = tab_data_[tab_index].tab->data();
496 if ((size_t)data.common_prefix_length != prefix_lengths[tab_index]) {
sky 2011/02/25 17:02:07 static_cast
MAD 2011/02/25 20:09:13 Oops... I meant to fix that and forgot... Sorry ab
497 data.common_prefix_length = prefix_lengths[tab_index];
498 tab_data_[tab_index].tab->SetData(data);
sky 2011/02/25 17:02:07 I think you need a SchedulePaint here.
MAD 2011/02/25 20:09:13 I was wondering about that, but the SetData implem
sky 2011/02/25 21:04:44 It does? It probably should, but I don't think it
MAD 2011/02/25 21:49:24 Actually, it indirectly does, via Layout, which do
sky 2011/02/25 22:59:27 BaseTab doesn't have a LayoutManager though.
499 }
500 }
407 } 501 }
408 502
409 int BaseTabStrip::TabIndexOfTab(BaseTab* tab) const { 503 int BaseTabStrip::TabIndexOfTab(BaseTab* tab) const {
410 for (int i = 0; i < tab_count(); ++i) { 504 for (int i = 0; i < tab_count(); ++i) {
411 if (base_tab_at_tab_index(i) == tab) 505 if (base_tab_at_tab_index(i) == tab)
412 return i; 506 return i;
413 } 507 }
414 return -1; 508 return -1;
415 } 509 }
416 510
(...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after
488 582
489 StopAnimating(false); 583 StopAnimating(false);
490 584
491 GenerateIdealBounds(); 585 GenerateIdealBounds();
492 586
493 for (int i = 0; i < tab_count(); ++i) 587 for (int i = 0; i < tab_count(); ++i)
494 tab_data_[i].tab->SetBoundsRect(tab_data_[i].ideal_bounds); 588 tab_data_[i].tab->SetBoundsRect(tab_data_[i].ideal_bounds);
495 589
496 SchedulePaint(); 590 SchedulePaint();
497 } 591 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698