gnome-shell/js/ui/docDisplay.js
Marina Zhurakhinskaya 4406943fd8 Check if the file still exists when displaying matches for the search.
Use get_modified() instead of get_visited() for GtkRecentInfo as get_modified() seems to reflect when the file was last modified or visted, while get_visited() stays the same as get_added(). See http://bugzilla.gnome.org/show_bug.cgi?id=567094

svn path=/trunk/; revision=141
2009-01-08 23:31:23 +00:00

192 lines
7.3 KiB
JavaScript

/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
const Signals = imports.signals;
const Clutter = imports.gi.Clutter;
const Gio = imports.gi.Gio;
const Gtk = imports.gi.Gtk;
const Shell = imports.gi.Shell;
const GenericDisplay = imports.ui.genericDisplay;
/* This class represents a single display item containing information about a document.
*
* docInfo - GtkRecentInfo object containing information about the document
* availableWidth - total width available for the item
*/
function DocDisplayItem(docInfo, availableWidth) {
this._init(docInfo, availableWidth);
}
DocDisplayItem.prototype = {
__proto__: GenericDisplay.GenericDisplayItem.prototype,
_init : function(docInfo, availableWidth) {
GenericDisplay.GenericDisplayItem.prototype._init.call(this, availableWidth);
this._docInfo = docInfo;
let name = docInfo.get_display_name();
// we can possibly display tags in the space for description in the future
let description = "";
let icon = new Clutter.Texture({width: 48, height: 48});
Shell.clutter_texture_set_from_pixbuf(icon, docInfo.get_icon(48));
this._setItemInfo(name, description, icon);
},
//// Public methods ////
// Returns the document info associated with this display item.
getDocInfo : function() {
return this._docInfo;
},
//// Public method overrides ////
// Opens a document represented by this display item.
launch : function() {
let appName = this._docInfo.last_application();
let appData = this._docInfo.get_application_info(appName);
let success = appData[0];
let appExec = appData[1];
let count = appData[2];
let time = appData[3];
if (success) {
log("Will open a document with the following command: " + appExec);
// TODO: Change this once better support for creating GAppInfo is added to
// GtkRecentInfo, as right now this relies on the fact that the file uri is
// already a part of appExec, so we don't supply any files to appInfo.launch().
let appInfo = Gio.app_info_create_from_commandline(appExec, null, 0, null);
appInfo.launch([], null, null);
} else {
log("Failed to get application info for " + this._docInfo.get_uri());
}
}
};
/* This class represents a display containing a collection of document items.
* The documents are sorted by how recently they were last visited.
*
* width - width available for the display
* height - height available for the display
*/
function DocDisplay(width, height) {
this._init(width, height);
}
DocDisplay.prototype = {
__proto__: GenericDisplay.GenericDisplay.prototype,
_init : function(width, height) {
GenericDisplay.GenericDisplay.prototype._init.call(this, width, height);
let me = this;
this._recentManager = Gtk.RecentManager.get_default();
this._docsStale = true;
this._recentManager.connect('changed', function(recentManager, userData) {
me._docsStale = true;
// Changes in local recent files should not happen when we are in the overlay mode,
// but redisplaying right away is cool when we use Zephyr.
// Also, we might be displaying remote documents, like Google Docs, in the future
// which might be edited by someone else.
me._redisplay();
});
},
//// Protected method overrides ////
// Gets the list of recent items from the recent items manager.
_refreshCache : function() {
let me = this;
if (!this._docsStale)
return;
this._allItems = {};
let docs = this._recentManager.get_items();
for (let i = 0; i < docs.length; i++) {
let docInfo = docs[i];
let docId = docInfo.get_uri();
// we use GtkRecentInfo URI as an item Id
this._allItems[docId] = docInfo;
}
this._docsStale = false;
},
// Sets the list of the displayed items based on how recently they were last visited.
_setDefaultList : function() {
this._removeAllDisplayItems();
// It seems to be an implementation detail of the Mozilla JavaScript that object
// properties are returned during the iteration in the same order in which they were
// defined, but it is not a guarantee according to this
// https://developer.mozilla.org/en/Core_JavaScript_1.5_Reference/Statements/for...in
// While this._allItems associative array seems to always be ordered by last added,
// as the results of this._recentManager.get_items() based on which it is constructed are,
// we should do the sorting manually because we want the order to be based on last visited.
// TODO: would it be better to store an additional array of doc ids as they are
// returned by this._recentManager.get_items() to avoid having to do this sorting?
// This function is called each time the search string is set back to '', so we are
// doing the sorting over the same items multiple times.
let docIds = [];
for (docId in this._allItems) {
docIds.push(docId);
}
this._sortItems(docIds);
let added = 0;
for (let i = 0; i < docIds.length && added < this._maxItems; i++) {
let docInfo = this._allItems[docIds[i]];
// docInfo.exists() checks if the resource still exists
if (docInfo.exists()) {
this._addDisplayItem(docIds[i]);
added += 1;
}
}
},
// Sorts the list of item ids in-place based on how recently the items associated with
// the ids were last visited.
_sortItems : function(itemIds) {
let me = this;
itemIds.sort(function (a,b) {
let docA = me._allItems[a];
let docB = me._allItems[b];
// We actually used get_modified() instead of get_visited() here, as GtkRecentInfo
// doesn't updated get_visited() correctly.
// See http://bugzilla.gnome.org/show_bug.cgi?id=567094
if (docA.get_modified() > docB.get_modified())
return -1;
else if (docA.get_modified() < docB.get_modified())
return 1;
else
return 0;
});
},
// Checks if the item info can be a match for the search string by checking
// the name of the document. Item info is expected to be GtkRecentInfo.
// Returns a boolean flag indicating if itemInfo is a match.
_isInfoMatching : function(itemInfo, search) {
if (!itemInfo.exists())
return false;
if (search == null || search == '')
return true;
let name = itemInfo.get_display_name().toLowerCase();
if (name.indexOf(search) >= 0)
return true;
// TODO: we can also check doc URIs, so that
// if you search for a directory name, we display recent files from it
return false;
},
// Creates a DocDisplayItem based on itemInfo, which is expected be a GtkRecentInfo object.
_createDisplayItem: function(itemInfo) {
return new DocDisplayItem(itemInfo, this._width);
}
};
Signals.addSignalMethods(DocDisplay.prototype);