appDisplay: Move from instanceof-testing to polymorphic duck typing

Instead of having _compareItems, _getItemId, etc. on the view to
pull out info about items, use the AppIcon / FolderIcon items we
create as a place to track this additional info. We now require
that these items have a '.id' property for deduplication, and a
'.name' property to sort by.

https://bugzilla.gnome.org/show_bug.cgi?id=722117
This commit is contained in:
Jasper St. Pierre 2013-12-15 22:18:17 -05:00
parent 933f38390b
commit 8fe7f923ec

View File

@ -102,40 +102,22 @@ const BaseAppView = new Lang.Class({
this._allItems = []; this._allItems = [];
}, },
_getItemId: function(item) { _addItem: function(icon) {
throw new Error('Not implemented'); let id = icon.id;
},
_createItemIcon: function(item) {
throw new Error('Not implemented');
},
_compareItems: function(a, b) {
throw new Error('Not implemented');
},
_addItem: function(item) {
let id = this._getItemId(item);
if (this._items[id] !== undefined) if (this._items[id] !== undefined)
return null; return;
let itemIcon = this._createItemIcon(item); this._allItems.push(icon);
this._allItems.push(item); this._items[id] = icon;
this._items[id] = itemIcon;
return itemIcon;
}, },
loadGrid: function() { loadGrid: function() {
this._allItems.sort(Lang.bind(this, this._compareItems)); this._allItems.sort(Lang.bind(this, function(a, b) {
return a.name.localeCompare(b.name);
for (let i = 0; i < this._allItems.length; i++) { }));
let id = this._getItemId(this._allItems[i]); this._allItems.forEach(Lang.bind(this, function(item) {
if (!id) this._grid.addItem(item);
continue; }));
this._grid.addItem(this._items[id]);
}
this.emit('view-loaded'); this.emit('view-loaded');
}, },
@ -472,50 +454,26 @@ const AllView = new Lang.Class({
return Clutter.EVENT_PROPAGATE; return Clutter.EVENT_PROPAGATE;
}, },
_getItemId: function(item) {
if (item instanceof Shell.App)
return item.get_id();
else if (item instanceof GMenu.TreeDirectory)
return item.get_menu_id();
else
return null;
},
_createItemIcon: function(item) {
if (item instanceof Shell.App)
return new AppIcon(item);
else if (item instanceof GMenu.TreeDirectory)
return new FolderIcon(item, this);
else
return null;
},
_compareItems: function(itemA, itemB) {
// bit of a hack: rely on both ShellApp and GMenuTreeDirectory
// having a get_name() method
let nameA = GLib.utf8_collate_key(itemA.get_name(), -1);
let nameB = GLib.utf8_collate_key(itemB.get_name(), -1);
return (nameA > nameB) ? 1 : (nameA < nameB ? -1 : 0);
},
removeAll: function() { removeAll: function() {
this._folderIcons = []; this._folderIcons = [];
this.parent(); this.parent();
}, },
addApp: function(app) { addApp: function(app) {
let appIcon = this._addItem(app); let icon = new AppIcon(app);
if (appIcon) this._addItem(icon);
appIcon.actor.connect('key-focus-in', if (icon)
Lang.bind(this, this._ensureIconVisible)); icon.actor.connect('key-focus-in',
Lang.bind(this, this._ensureIconVisible));
}, },
addFolder: function(dir) { addFolder: function(dir) {
let folderIcon = this._addItem(dir); let icon = new FolderIcon(dir, this);
this._folderIcons.push(folderIcon); this._addItem(icon);
if (folderIcon) this._folderIcons.push(icon);
folderIcon.actor.connect('key-focus-in', if (icon)
Lang.bind(this, this._ensureIconVisible)); icon.actor.connect('key-focus-in',
Lang.bind(this, this._ensureIconVisible));
}, },
addFolderPopup: function(popup) { addFolderPopup: function(popup) {
@ -961,20 +919,9 @@ const FolderView = new Lang.Class({
this.actor.add_action(action); this.actor.add_action(action);
}, },
_getItemId: function(item) {
return item.get_id();
},
_createItemIcon: function(item) {
return new AppIcon(item);
},
_compareItems: function(a, b) {
return a.compare_by_name(b);
},
addApp: function(app) { addApp: function(app) {
this._addItem(app); let icon = new AppIcon(app);
this._addItem(icon);
}, },
createFolderIcon: function(size) { createFolderIcon: function(size) {
@ -985,7 +932,7 @@ const FolderView = new Lang.Class({
let aligns = [ Clutter.ActorAlign.START, Clutter.ActorAlign.END ]; let aligns = [ Clutter.ActorAlign.START, Clutter.ActorAlign.END ];
for (let i = 0; i < Math.min(this._allItems.length, 4); i++) { for (let i = 0; i < Math.min(this._allItems.length, 4); i++) {
let texture = this._allItems[i].create_icon_texture(subSize); let texture = this._allItems[i].app.create_icon_texture(subSize);
let bin = new St.Bin({ child: texture, let bin = new St.Bin({ child: texture,
x_expand: true, y_expand: true }); x_expand: true, y_expand: true });
bin.set_x_align(aligns[i % 2]); bin.set_x_align(aligns[i % 2]);
@ -1064,6 +1011,9 @@ const FolderIcon = new Lang.Class({
_init: function(dir, parentView) { _init: function(dir, parentView) {
this._dir = dir; this._dir = dir;
this.id = dir.get_menu_id();
this.name = dir.get_name();
this._parentView = parentView; this._parentView = parentView;
this.actor = new St.Button({ style_class: 'app-well-app app-folder', this.actor = new St.Button({ style_class: 'app-well-app app-folder',
@ -1076,8 +1026,7 @@ const FolderIcon = new Lang.Class({
// whether we need to update arrow side, position etc. // whether we need to update arrow side, position etc.
this._popupInvalidated = false; this._popupInvalidated = false;
let label = this._dir.get_name(); this.icon = new IconGrid.BaseIcon(this.name,
this.icon = new IconGrid.BaseIcon(label,
{ createIcon: Lang.bind(this, this._createIcon), setSizeManually: true }); { createIcon: Lang.bind(this, this._createIcon), setSizeManually: true });
this.actor.set_child(this.icon.actor); this.actor.set_child(this.icon.actor);
this.actor.label_actor = this.icon.label; this.actor.label_actor = this.icon.label;
@ -1293,6 +1242,9 @@ const AppIcon = new Lang.Class({
_init : function(app, iconParams) { _init : function(app, iconParams) {
this.app = app; this.app = app;
this.id = app.get_id();
this.name = app.get_name();
this.actor = new St.Button({ style_class: 'app-well-app', this.actor = new St.Button({ style_class: 'app-well-app',
reactive: true, reactive: true,
button_mask: St.ButtonMask.ONE | St.ButtonMask.TWO, button_mask: St.ButtonMask.ONE | St.ButtonMask.TWO,