dash: Make recent docs display two columns
The design has smaller icons in two columns. Add a new custom display to docDisplay for it. Clean up some of the texture cache handling for recent URIs so it's not size-dependent, since the dash size is now different from the default GenericDisplay size.
This commit is contained in:
parent
dd1a309cb6
commit
2dcd0511c4
@ -85,19 +85,18 @@ DocInfo.prototype = {
|
|||||||
|
|
||||||
var docManagerInstance = null;
|
var docManagerInstance = null;
|
||||||
|
|
||||||
function getDocManager(size) {
|
function getDocManager() {
|
||||||
if (docManagerInstance == null)
|
if (docManagerInstance == null)
|
||||||
docManagerInstance = new DocManager(size);
|
docManagerInstance = new DocManager();
|
||||||
return docManagerInstance;
|
return docManagerInstance;
|
||||||
}
|
}
|
||||||
|
|
||||||
function DocManager(size) {
|
function DocManager() {
|
||||||
this._init(size);
|
this._init();
|
||||||
}
|
}
|
||||||
|
|
||||||
DocManager.prototype = {
|
DocManager.prototype = {
|
||||||
_init: function(iconSize) {
|
_init: function() {
|
||||||
this._iconSize = iconSize;
|
|
||||||
this._recentManager = Gtk.RecentManager.get_default();
|
this._recentManager = Gtk.RecentManager.get_default();
|
||||||
this._items = {};
|
this._items = {};
|
||||||
this._recentManager.connect('changed', Lang.bind(this, function(recentManager) {
|
this._recentManager.connect('changed', Lang.bind(this, function(recentManager) {
|
||||||
@ -112,6 +111,9 @@ DocManager.prototype = {
|
|||||||
let newItems = {};
|
let newItems = {};
|
||||||
for (let i = 0; i < docs.length; i++) {
|
for (let i = 0; i < docs.length; i++) {
|
||||||
let recentInfo = docs[i];
|
let recentInfo = docs[i];
|
||||||
|
if (!recentInfo.exists())
|
||||||
|
continue;
|
||||||
|
|
||||||
let docInfo = new DocInfo(recentInfo);
|
let docInfo = new DocInfo(recentInfo);
|
||||||
|
|
||||||
// we use GtkRecentInfo URI as an item Id
|
// we use GtkRecentInfo URI as an item Id
|
||||||
@ -126,7 +128,7 @@ DocManager.prototype = {
|
|||||||
dump them here */
|
dump them here */
|
||||||
let texCache = Shell.TextureCache.get_default();
|
let texCache = Shell.TextureCache.get_default();
|
||||||
for (var uri in deleted) {
|
for (var uri in deleted) {
|
||||||
texCache.evict_recent_thumbnail(this._iconSize, this._items[uri]);
|
texCache.evict_recent_thumbnail(this._items[uri]);
|
||||||
}
|
}
|
||||||
this._items = newItems;
|
this._items = newItems;
|
||||||
},
|
},
|
||||||
|
@ -64,7 +64,6 @@ const PANE_BORDER_WIDTH = 2;
|
|||||||
const PANE_BACKGROUND_COLOR = new Clutter.Color();
|
const PANE_BACKGROUND_COLOR = new Clutter.Color();
|
||||||
PANE_BACKGROUND_COLOR.from_pixel(0x000000f4);
|
PANE_BACKGROUND_COLOR.from_pixel(0x000000f4);
|
||||||
|
|
||||||
|
|
||||||
function Pane() {
|
function Pane() {
|
||||||
this._init();
|
this._init();
|
||||||
}
|
}
|
||||||
@ -604,10 +603,8 @@ Dash.prototype = {
|
|||||||
|
|
||||||
let docsSection = new Section(_("RECENT DOCUMENTS"));
|
let docsSection = new Section(_("RECENT DOCUMENTS"));
|
||||||
|
|
||||||
let docDisplay = new DocDisplay.DocDisplay();
|
let docDisplay = new DocDisplay.DashDocDisplay();
|
||||||
docDisplay.load();
|
|
||||||
docsSection.content.append(docDisplay.actor, Big.BoxPackFlags.EXPAND);
|
docsSection.content.append(docDisplay.actor, Big.BoxPackFlags.EXPAND);
|
||||||
createPaneForDetails(this, docDisplay);
|
|
||||||
|
|
||||||
this._moreDocsPane = null;
|
this._moreDocsPane = null;
|
||||||
docsSection.header.moreLink.connect('activated', Lang.bind(this, function (link) {
|
docsSection.header.moreLink.connect('activated', Lang.bind(this, function (link) {
|
||||||
|
@ -1,17 +1,24 @@
|
|||||||
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
|
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
|
||||||
|
|
||||||
|
const Big = imports.gi.Big;
|
||||||
const Clutter = imports.gi.Clutter;
|
const Clutter = imports.gi.Clutter;
|
||||||
const Gio = imports.gi.Gio;
|
const Gio = imports.gi.Gio;
|
||||||
const Gtk = imports.gi.Gtk;
|
const Gtk = imports.gi.Gtk;
|
||||||
const Lang = imports.lang;
|
const Lang = imports.lang;
|
||||||
|
const Pango = imports.gi.Pango;
|
||||||
const Shell = imports.gi.Shell;
|
const Shell = imports.gi.Shell;
|
||||||
const Signals = imports.signals;
|
const Signals = imports.signals;
|
||||||
const Mainloop = imports.mainloop;
|
const Mainloop = imports.mainloop;
|
||||||
|
|
||||||
const DocInfo = imports.misc.docInfo;
|
const DocInfo = imports.misc.docInfo;
|
||||||
|
const DND = imports.ui.dnd;
|
||||||
const GenericDisplay = imports.ui.genericDisplay;
|
const GenericDisplay = imports.ui.genericDisplay;
|
||||||
const Main = imports.ui.main;
|
const Main = imports.ui.main;
|
||||||
|
|
||||||
|
const DASH_DOCS_ICON_SIZE = 16;
|
||||||
|
|
||||||
|
const DEFAULT_SPACING = 4;
|
||||||
|
|
||||||
/* This class represents a single display item containing information about a document.
|
/* This class represents a single display item containing information about a document.
|
||||||
* We take the current number of seconds in the constructor to avoid looking up the current
|
* We take the current number of seconds in the constructor to avoid looking up the current
|
||||||
* time for every item when they are created in a batch.
|
* time for every item when they are created in a batch.
|
||||||
@ -123,7 +130,7 @@ DocDisplay.prototype = {
|
|||||||
this._updateTimeoutTargetTime = -1;
|
this._updateTimeoutTargetTime = -1;
|
||||||
this._updateTimeoutId = 0;
|
this._updateTimeoutId = 0;
|
||||||
|
|
||||||
this._docManager = DocInfo.getDocManager(GenericDisplay.ITEM_DISPLAY_ICON_SIZE);
|
this._docManager = DocInfo.getDocManager();
|
||||||
this._docsStale = true;
|
this._docsStale = true;
|
||||||
this._docManager.connect('changed', function(mgr, userData) {
|
this._docManager.connect('changed', function(mgr, userData) {
|
||||||
me._docsStale = true;
|
me._docsStale = true;
|
||||||
@ -249,3 +256,183 @@ DocDisplay.prototype = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
Signals.addSignalMethods(DocDisplay.prototype);
|
Signals.addSignalMethods(DocDisplay.prototype);
|
||||||
|
|
||||||
|
function DashDocDisplayItem(docInfo) {
|
||||||
|
this._init(docInfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
DashDocDisplayItem.prototype = {
|
||||||
|
_init: function(docInfo) {
|
||||||
|
this._info = docInfo;
|
||||||
|
this.actor = new Big.Box({ orientation: Big.BoxOrientation.HORIZONTAL,
|
||||||
|
spacing: DEFAULT_SPACING,
|
||||||
|
reactive: true });
|
||||||
|
this.actor.connect('button-release-event', Lang.bind(this, function () {
|
||||||
|
docInfo.launch();
|
||||||
|
Main.overview.hide();
|
||||||
|
}));
|
||||||
|
|
||||||
|
this._icon = docInfo.createIcon(DASH_DOCS_ICON_SIZE);
|
||||||
|
let iconBox = new Big.Box({ y_align: Big.BoxAlignment.CENTER });
|
||||||
|
iconBox.append(this._icon, Big.BoxPackFlags.NONE);
|
||||||
|
this.actor.append(iconBox, Big.BoxPackFlags.NONE);
|
||||||
|
let name = new Clutter.Text({ font_name: "Sans 14px",
|
||||||
|
color: GenericDisplay.ITEM_DISPLAY_NAME_COLOR,
|
||||||
|
ellipsize: Pango.EllipsizeMode.END,
|
||||||
|
text: docInfo.name });
|
||||||
|
this.actor.append(name, Big.BoxPackFlags.EXPAND);
|
||||||
|
|
||||||
|
let draggable = DND.makeDraggable(this.actor);
|
||||||
|
this.actor._delegate = this;
|
||||||
|
},
|
||||||
|
|
||||||
|
getDragActorSource: function() {
|
||||||
|
return this._icon;
|
||||||
|
},
|
||||||
|
|
||||||
|
getDragActor: function(stageX, stageY) {
|
||||||
|
this.dragActor = this._info.createIcon(DASH_DOCS_ICON_SIZE);
|
||||||
|
return this.dragActor;
|
||||||
|
},
|
||||||
|
|
||||||
|
//// Drag and drop functions ////
|
||||||
|
|
||||||
|
shellWorkspaceLaunch: function () {
|
||||||
|
this._info.launch();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class used to display two column recent documents in the dash
|
||||||
|
*/
|
||||||
|
function DashDocDisplay() {
|
||||||
|
this._init();
|
||||||
|
}
|
||||||
|
|
||||||
|
DashDocDisplay.prototype = {
|
||||||
|
_init: function() {
|
||||||
|
this.actor = new Shell.GenericContainer();
|
||||||
|
this.actor.connect('get-preferred-width', Lang.bind(this, this._getPreferredWidth));
|
||||||
|
this.actor.connect('get-preferred-height', Lang.bind(this, this._getPreferredHeight));
|
||||||
|
this.actor.connect('allocate', Lang.bind(this, this._allocate));
|
||||||
|
|
||||||
|
this._docManager = DocInfo.getDocManager();
|
||||||
|
this._docManager.connect('changed', Lang.bind(this, function(mgr) {
|
||||||
|
this._redisplay();
|
||||||
|
}));
|
||||||
|
this._redisplay();
|
||||||
|
},
|
||||||
|
|
||||||
|
_getPreferredWidth: function(actor, forHeight, alloc) {
|
||||||
|
let children = actor.get_children();
|
||||||
|
|
||||||
|
// We use two columns maximum. Just take the min and natural size of the
|
||||||
|
// first two items, even though strictly speaking it's not correct; we'd
|
||||||
|
// need to calculate how many items we could fit for the height, then
|
||||||
|
// take the biggest preferred width for each column.
|
||||||
|
// In practice the dash gets a fixed width anyways.
|
||||||
|
|
||||||
|
// If we have one child, add its minimum and natural size
|
||||||
|
if (children.length > 0) {
|
||||||
|
let [minSize, naturalSize] = children[0].get_preferred_width(forHeight);
|
||||||
|
alloc.min_size += minSize;
|
||||||
|
alloc.natural_size += naturalSize;
|
||||||
|
}
|
||||||
|
// If we have two, add its size, plus DEFAULT_SPACING
|
||||||
|
if (children.length > 1) {
|
||||||
|
let [minSize, naturalSize] = children[1].get_preferred_width(forHeight);
|
||||||
|
alloc.min_size += DEFAULT_SPACING + minSize;
|
||||||
|
alloc.natural_size += DEFAULT_SPACING + naturalSize;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
_getPreferredHeight: function(actor, forWidth, alloc) {
|
||||||
|
let children = actor.get_children();
|
||||||
|
|
||||||
|
// Two columns, where we go vertically down first. So just take
|
||||||
|
// the height of half of the children as our preferred height.
|
||||||
|
|
||||||
|
let firstColumnChildren = children.length / 2;
|
||||||
|
|
||||||
|
alloc.min_size = 0;
|
||||||
|
for (let i = 0; i < firstColumnChildren; i++) {
|
||||||
|
let child = children[i];
|
||||||
|
let [minSize, naturalSize] = child.get_preferred_height(forWidth);
|
||||||
|
alloc.natural_size += naturalSize;
|
||||||
|
|
||||||
|
if (i > 0 && i < children.length - 1) {
|
||||||
|
alloc.min_size += DEFAULT_SPACING;
|
||||||
|
alloc.natural_size += DEFAULT_SPACING;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
_allocate: function(actor, box, flags) {
|
||||||
|
let width = box.x2 - box.x1;
|
||||||
|
let height = box.y2 - box.y1;
|
||||||
|
|
||||||
|
let children = actor.get_children();
|
||||||
|
|
||||||
|
// The width of an item is our allocated width, minus spacing, divided in half.
|
||||||
|
let itemWidth = Math.floor((width - DEFAULT_SPACING) / 2);
|
||||||
|
let x = box.x1;
|
||||||
|
let y = box.y1;
|
||||||
|
let columnIndex = 0;
|
||||||
|
let i = 0;
|
||||||
|
// Loop over the children, going vertically down first. When we run
|
||||||
|
// out of vertical space (our y variable is bigger than box.y2), switch
|
||||||
|
// to the second column.
|
||||||
|
for (; i < children.length; i++) {
|
||||||
|
let child = children[i];
|
||||||
|
|
||||||
|
let [minSize, naturalSize] = child.get_preferred_height(-1);
|
||||||
|
|
||||||
|
if (y + naturalSize > box.y2) {
|
||||||
|
// Is this the second column? Ok, break.
|
||||||
|
if (columnIndex == 1) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
// Set x to the halfway point.
|
||||||
|
columnIndex += 1;
|
||||||
|
x = x + itemWidth + DEFAULT_SPACING;
|
||||||
|
// And y is back to the top.
|
||||||
|
y = box.y1;
|
||||||
|
}
|
||||||
|
|
||||||
|
let childBox = new Clutter.ActorBox();
|
||||||
|
childBox.x1 = x;
|
||||||
|
childBox.y1 = y;
|
||||||
|
childBox.x2 = childBox.x1 + itemWidth;
|
||||||
|
childBox.y2 = y + naturalSize;
|
||||||
|
|
||||||
|
y = childBox.y2 + DEFAULT_SPACING;
|
||||||
|
|
||||||
|
child.show();
|
||||||
|
child.allocate(childBox, flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Everything else didn't fit, just hide it.
|
||||||
|
for (; i < children.length; i++) {
|
||||||
|
children[i].hide();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
_redisplay: function() {
|
||||||
|
this.actor.remove_all();
|
||||||
|
|
||||||
|
let docs = this._docManager.getItems();
|
||||||
|
let docUrls = [];
|
||||||
|
for (let url in docs) {
|
||||||
|
docUrls.push(url);
|
||||||
|
}
|
||||||
|
docUrls.sort(function (urlA, urlB) { return docs[urlB].timestamp - docs[urlA].timestamp; });
|
||||||
|
let textureCache = Shell.TextureCache.get_default();
|
||||||
|
|
||||||
|
for (let i = 0; i < docUrls.length; i++) {
|
||||||
|
let url = docUrls[i];
|
||||||
|
let docInfo = docs[url];
|
||||||
|
let display = new DashDocDisplayItem(docInfo);
|
||||||
|
this.actor.add_actor(display.actor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -1196,47 +1196,44 @@ shell_texture_cache_load_recent_thumbnail (ShellTextureCache *cache,
|
|||||||
/**
|
/**
|
||||||
* shell_texture_cache_evict_thumbnail:
|
* shell_texture_cache_evict_thumbnail:
|
||||||
* @cache:
|
* @cache:
|
||||||
* @size: Size in pixels
|
|
||||||
* @uri: Source URI
|
* @uri: Source URI
|
||||||
*
|
*
|
||||||
* Removes the reference the shell_texture_cache_load_thumbnail() function
|
* Removes all references added by shell_texture_cache_load_thumbnail() function
|
||||||
* created for a thumbnail.
|
* created for the given URI.
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
shell_texture_cache_evict_thumbnail (ShellTextureCache *cache,
|
shell_texture_cache_evict_thumbnail (ShellTextureCache *cache,
|
||||||
int size,
|
|
||||||
const char *uri)
|
const char *uri)
|
||||||
{
|
{
|
||||||
CacheKey key;
|
GHashTableIter iter;
|
||||||
|
gpointer key, value;
|
||||||
|
|
||||||
memset (&key, 0, sizeof(key));
|
g_hash_table_iter_init (&iter, cache->priv->keyed_cache);
|
||||||
key.size = size;
|
|
||||||
key.thumbnail_uri = (char*)uri;
|
|
||||||
|
|
||||||
g_hash_table_remove (cache->priv->keyed_cache, &key);
|
while (g_hash_table_iter_next (&iter, &key, &value))
|
||||||
|
{
|
||||||
|
CacheKey *cachekey = key;
|
||||||
|
|
||||||
|
if (cachekey->thumbnail_uri == NULL || strcmp (cachekey->thumbnail_uri, uri) != 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
g_hash_table_iter_remove (&iter);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* shell_texture_cache_evict_recent_thumbnail:
|
* shell_texture_cache_evict_recent_thumbnail:
|
||||||
* @cache:
|
* @cache:
|
||||||
* @size: Size in pixels
|
|
||||||
* @info: A recent info
|
* @info: A recent info
|
||||||
*
|
*
|
||||||
* Removes the reference the shell_texture_cache_load_recent_thumbnail() function
|
* Removes all references added by shell_texture_cache_load_recent_thumbnail() function
|
||||||
* created for a thumbnail.
|
* for the URI associated with the given @info.
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
shell_texture_cache_evict_recent_thumbnail (ShellTextureCache *cache,
|
shell_texture_cache_evict_recent_thumbnail (ShellTextureCache *cache,
|
||||||
int size,
|
|
||||||
GtkRecentInfo *info)
|
GtkRecentInfo *info)
|
||||||
{
|
{
|
||||||
CacheKey key;
|
shell_texture_cache_evict_thumbnail (cache, gtk_recent_info_get_uri (info));
|
||||||
|
|
||||||
memset (&key, 0, sizeof(key));
|
|
||||||
key.size = size;
|
|
||||||
key.thumbnail_uri = (char*)gtk_recent_info_get_uri (info);
|
|
||||||
|
|
||||||
g_hash_table_remove (cache->priv->keyed_cache, &key);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static ShellTextureCache *instance = NULL;
|
static ShellTextureCache *instance = NULL;
|
||||||
|
@ -62,11 +62,9 @@ ClutterActor *shell_texture_cache_load_recent_thumbnail (ShellTextureCache *cach
|
|||||||
GtkRecentInfo *info);
|
GtkRecentInfo *info);
|
||||||
|
|
||||||
void shell_texture_cache_evict_thumbnail (ShellTextureCache *cache,
|
void shell_texture_cache_evict_thumbnail (ShellTextureCache *cache,
|
||||||
int size,
|
|
||||||
const char *uri);
|
const char *uri);
|
||||||
|
|
||||||
void shell_texture_cache_evict_recent_thumbnail (ShellTextureCache *cache,
|
void shell_texture_cache_evict_recent_thumbnail (ShellTextureCache *cache,
|
||||||
int size,
|
|
||||||
GtkRecentInfo *info);
|
GtkRecentInfo *info);
|
||||||
|
|
||||||
ClutterActor *shell_texture_cache_load_uri_async (ShellTextureCache *cache,
|
ClutterActor *shell_texture_cache_load_uri_async (ShellTextureCache *cache,
|
||||||
|
Loading…
Reference in New Issue
Block a user