Index: chrome/browser/ui/views/tabs/base_tab_strip.cc |
=================================================================== |
--- chrome/browser/ui/views/tabs/base_tab_strip.cc (revision 75998) |
+++ chrome/browser/ui/views/tabs/base_tab_strip.cc (working copy) |
@@ -4,10 +4,16 @@ |
#include "chrome/browser/ui/views/tabs/base_tab_strip.h" |
+#include <vector> |
+ |
+#include "base/command_line.h" |
+#include "base/hash_tables.h" |
#include "base/logging.h" |
+#include "base/string_split.h" |
#include "chrome/browser/ui/view_ids.h" |
#include "chrome/browser/ui/views/tabs/dragged_tab_controller.h" |
#include "chrome/browser/ui/views/tabs/tab_strip_controller.h" |
+#include "chrome/common/chrome_switches.h" |
#include "views/widget/root_view.h" |
#include "views/window/window.h" |
@@ -145,6 +151,7 @@ |
TabData d = { tab, gfx::Rect() }; |
tab_data_.insert(tab_data_.begin() + ModelIndexToTabIndex(model_index), d); |
+ UpdateCommonTitlePrefix(); |
AddChildView(tab); |
@@ -175,6 +182,7 @@ |
BaseTab* tab = GetBaseTabAtModelIndex(model_index); |
bool mini_state_changed = tab->data().mini != data.mini; |
tab->SetData(data); |
+ UpdateCommonTitlePrefix(); |
tab->SchedulePaint(); |
if (mini_state_changed) { |
@@ -404,8 +412,94 @@ |
tab_data_.erase(tab_data_.begin() + tab_data_index); |
delete tab; |
+ UpdateCommonTitlePrefix(); |
} |
+void BaseTabStrip::UpdateCommonTitlePrefix() { |
+ // Hidden behind a command line flag until we want to enable it always. |
+ if (!CommandLine::ForCurrentProcess()->HasSwitch( |
+ switches::kElideTabTitlePrefix)) { |
+ return; |
+ } |
+ |
+ // First, we need to identify if there are identical titles, |
+ // because we don't want to remove prefixes for those at all. |
+ // We do it as a separate pass so that we don't need to remove |
+ // previously parsed titles when we find a duplicate title later on. |
+ // This set will contain the indexes of the tab that have a duplicate. |
+ base::hash_set<int> no_prefix_tab; |
+ // This map is used to remember the existing title and the index of the |
+ // 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...
|
+ // no_prefix_tab set, we set the index to -1. |
+ base::hash_map<string16, int> existing_title; |
+ for (int tab_index = 0; tab_index < tab_count(); ++tab_index) { |
+ 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.
|
+ // We use pairs to test existence and insert in one shot. |
+ std::pair<base::hash_map<string16, int>::iterator, bool> insert_result = |
+ existing_title.insert( |
+ std::make_pair(tab_data_[tab_index].tab->data().title, tab_index)); |
+ if (!insert_result.second) { |
+ 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...
|
+ insert_result.first->first); |
+ no_prefix_tab.insert(tab_index); |
+ if (insert_result.first->second != -1) { |
+ no_prefix_tab.insert(insert_result.first->second); |
+ insert_result.first->second = -1; |
+ } |
+ } |
+ } |
+ |
+ // This next loop accumulates all the potential prefixes, |
+ // and remember on which tabs we saw them. |
+ 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...
|
+ for (int tab_index = 0; tab_index < tab_count(); ++tab_index) { |
+ const TabRendererData& tab_data = tab_data_[tab_index].tab->data(); |
+ // Mini, title-less, and duplicate title tabs |
+ // are not to be included in this process. |
+ if (tab_data.mini || tab_data.title.empty() || |
+ no_prefix_tab.find(tab_index) != no_prefix_tab.end()) { |
+ continue; |
+ } |
+ |
+ // We only create prefixes at word boundaries. |
+ std::vector<string16> words; |
+ 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
|
+ size_t end_of_word = 0; |
+ // 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 :
|
+ 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
|
+ if (!words[word_index].empty()) { |
+ 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
|
+ words[word_index].size(); |
+ prefixes[tab_data.title.substr(0, end_of_word)].push_back(tab_index); |
+ } |
+ } |
+ } |
+ |
+ // Now we parse the map to find common prefixes and set the largest per tab. |
+ std::vector<size_t> prefix_lengths(tab_count(), 0); |
+ 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...
|
+ prefixes.begin(); |
+ for (; iter != prefixes.end(); ++iter) { |
+ if (iter->second.size() > 1) { // Need more than one with same prefix. |
+ size_t prefix_length = iter->first.size(); |
+ for (size_t index = 0; index < iter->second.size(); ++index){ |
+ if (prefix_lengths[iter->second[index]] < prefix_length) { |
+ prefix_lengths[iter->second[index]] = prefix_length; |
+ } |
+ } |
+ } |
+ } |
+ |
+ // And finally, reset the tab data for the tabs that changed. |
+ for (int tab_index = 0; tab_index < tab_count(); ++tab_index) { |
+ TabRendererData data = tab_data_[tab_index].tab->data(); |
+ 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
|
+ data.common_prefix_length = prefix_lengths[tab_index]; |
+ 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.
|
+ } |
+ } |
+} |
+ |
int BaseTabStrip::TabIndexOfTab(BaseTab* tab) const { |
for (int i = 0; i < tab_count(); ++i) { |
if (base_tab_at_tab_index(i) == tab) |