From 4ea2cc3bd4a7d9b1c54a9d33e6a1cf82e7c8c21d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rg=20Frings-F=C3=BCrst?= Date: Wed, 23 Jul 2014 09:06:59 +0200 Subject: Imported Upstream version 0.18.1 --- src/folders/Branch.vala | 198 ++++++++++++++++++++++++++++++++++++++++++++++ src/folders/Folders.vala | 35 ++++++++ src/folders/Page.vala | 41 ++++++++++ src/folders/mk/folders.mk | 31 ++++++++ 4 files changed, 305 insertions(+) create mode 100644 src/folders/Branch.vala create mode 100644 src/folders/Folders.vala create mode 100644 src/folders/Page.vala create mode 100644 src/folders/mk/folders.mk (limited to 'src/folders') diff --git a/src/folders/Branch.vala b/src/folders/Branch.vala new file mode 100644 index 0000000..bc5b578 --- /dev/null +++ b/src/folders/Branch.vala @@ -0,0 +1,198 @@ +/* Copyright 2012-2014 Yorba Foundation + * + * This software is licensed under the GNU Lesser General Public License + * (version 2.1 or later). See the COPYING file in this distribution. + */ + +public class Folders.Branch : Sidebar.Branch { + private Gee.HashMap entries = + new Gee.HashMap(file_hash, file_equal); + private File home_dir; + + public class Branch() { + base (new Folders.Root(), Sidebar.Branch.Options.STARTUP_OPEN_GROUPING, comparator); + + home_dir = File.new_for_path(Environment.get_home_dir()); + + foreach (MediaSourceCollection sources in MediaCollectionRegistry.get_instance().get_all()) { + // seed + on_media_contents_altered(sources.get_all(), null); + + // monitor + sources.contents_altered.connect(on_media_contents_altered); + } + } + + ~Branch() { + foreach (MediaSourceCollection sources in MediaCollectionRegistry.get_instance().get_all()) + sources.contents_altered.disconnect(on_media_contents_altered); + } + + private static int comparator(Sidebar.Entry a, Sidebar.Entry b) { + if (a == b) + return 0; + + int coll_key_equality = strcmp(((Folders.SidebarEntry) a).collation, + ((Folders.SidebarEntry) b).collation); + + if (coll_key_equality == 0) { + // Collation keys were the same, double-check that + // these really are the same string... + return strcmp(((Folders.SidebarEntry) a).get_sidebar_name(), + ((Folders.SidebarEntry) b).get_sidebar_name()); + } + + return coll_key_equality; + } + + private void on_master_source_replaced(MediaSource media_source, File old_file, File new_file) { + remove_entry(old_file); + add_entry(media_source); + } + + private void on_media_contents_altered(Gee.Iterable? added, Gee.Iterable? removed) { + if (added != null) { + foreach (DataObject object in added) { + add_entry((MediaSource) object); + ((MediaSource) object).master_replaced.connect(on_master_source_replaced); + } + } + + if (removed != null) { + foreach (DataObject object in removed) { + remove_entry(((MediaSource) object).get_file()); + ((MediaSource) object).master_replaced.disconnect(on_master_source_replaced); + } + } + } + + void add_entry(MediaSource media) { + File file = media.get_file(); + + Gee.ArrayList elements = new Gee.ArrayList(); + + // add the path elements in reverse order up to home directory + File? parent = file.get_parent(); + while (parent != null) { + // don't process paths above the user's home directory + if (parent.equal(home_dir.get_parent())) + break; + + elements.add(parent); + + parent = parent.get_parent(); + } + + // walk path elements in order from home directory down, building needed sidebar entries + // along the way + Folders.SidebarEntry? parent_entry = null; + for (int ctr = elements.size - 1; ctr >= 0; ctr--) { + File parent_dir = elements[ctr]; + + // save current parent, needed if this entry needs to be grafted + Folders.SidebarEntry? old_parent_entry = parent_entry; + + parent_entry = entries.get(parent_dir); + if (parent_entry == null) { + parent_entry = new Folders.SidebarEntry(parent_dir); + entries.set(parent_dir, parent_entry); + + graft((old_parent_entry == null) ? get_root() : old_parent_entry, parent_entry); + } + + // only increment entry's file count if File is going in this folder + if (ctr == 0) + parent_entry.count++; + } + } + + private void remove_entry(File file) { + Folders.SidebarEntry? folder_entry = entries.get(file.get_parent()); + if (folder_entry == null) + return; + + assert(folder_entry.count > 0); + + // decrement file count for folder of photo + if (--folder_entry.count > 0 || get_child_count(folder_entry) > 0) + return; + + // empty folder so prune tree + Folders.SidebarEntry? prune_point = folder_entry; + assert(prune_point != null); + + for (;;) { + bool removed = entries.unset(prune_point.dir); + assert(removed); + + Folders.SidebarEntry? parent = get_parent(prune_point) as Folders.SidebarEntry; + if (parent == null || parent.count != 0 || get_child_count(parent) > 1) + break; + + prune_point = parent; + } + + prune(prune_point); + } +} + +private class Folders.Root : Sidebar.Grouping { + public Root() { + base (_("Folders"), Folders.opened_icon, Folders.closed_icon); + } +} + +public class Folders.SidebarEntry : Sidebar.SimplePageEntry, Sidebar.ExpandableEntry { + public File dir { get; private set; } + public string collation { get; private set; } + + private int _count = 0; + public int count { + get { + return _count; + } + + set { + int prev_count = _count; + _count = value; + + // when count change 0->1 and 1->0 may need refresh icon + if ((prev_count == 0 && _count == 1) || (prev_count == 1 && _count == 0)) + sidebar_icon_changed(get_sidebar_icon()); + + } + } + + public SidebarEntry(File dir) { + this.dir = dir; + collation = g_utf8_collate_key_for_filename(dir.get_path()); + } + + public override string get_sidebar_name() { + return dir.get_basename(); + } + + public override Icon? get_sidebar_icon() { + return count == 0 ? closed_icon : have_photos_icon; + } + + public override string to_string() { + return dir.get_path(); + } + + public Icon? get_sidebar_open_icon() { + return count == 0 ? opened_icon : have_photos_icon; + } + + public Icon? get_sidebar_closed_icon() { + return count == 0 ? closed_icon : have_photos_icon; + } + + public bool expand_on_select() { + return true; + } + + protected override global::Page create_page() { + return new Folders.Page(dir); + } +} diff --git a/src/folders/Folders.vala b/src/folders/Folders.vala new file mode 100644 index 0000000..1cc14b1 --- /dev/null +++ b/src/folders/Folders.vala @@ -0,0 +1,35 @@ +/* Copyright 2012-2014 Yorba Foundation + * + * This software is licensed under the GNU Lesser General Public License + * (version 2.1 or later). See the COPYING file in this distribution. + */ + +/* This file is the master unit file for the Folders unit. It should be edited to include + * whatever code is deemed necessary. + * + * The init() and terminate() methods are mandatory. + * + * If the unit needs to be configured prior to initialization, add the proper parameters to + * the preconfigure() method, implement it, and ensure in init() that it's been called. + */ + +namespace Folders { + +static Icon? opened_icon = null; +static Icon? closed_icon = null; +static Icon? have_photos_icon = null; + +public void init() throws Error { + opened_icon = new ThemedIcon(Resources.ICON_FOLDER_OPEN); + closed_icon = new ThemedIcon(Resources.ICON_FOLDER_CLOSED); + have_photos_icon = new ThemedIcon(Resources.ICON_FOLDER_DOCUMENTS); +} + +public void terminate() { + opened_icon = null; + closed_icon = null; + have_photos_icon = null; +} + +} + diff --git a/src/folders/Page.vala b/src/folders/Page.vala new file mode 100644 index 0000000..d101e88 --- /dev/null +++ b/src/folders/Page.vala @@ -0,0 +1,41 @@ +/* Copyright 2012-2014 Yorba Foundation + * + * This software is licensed under the GNU Lesser General Public License + * (version 2.1 or later). See the COPYING file in this distribution. + */ + +public class Folders.Page : CollectionPage { + private class FolderViewManager : CollectionViewManager { + public File dir; + + public FolderViewManager(Folders.Page owner, File dir) { + base (owner); + + this.dir = dir; + } + + public override bool include_in_view(DataSource source) { + return ((MediaSource) source).get_file().has_prefix(dir); + } + } + + private FolderViewManager view_manager; + + public Page(File dir) { + base (dir.get_path()); + + view_manager = new FolderViewManager(this, dir); + + foreach (MediaSourceCollection sources in MediaCollectionRegistry.get_instance().get_all()) + get_view().monitor_source_collection(sources, view_manager, null); + } + + protected override void get_config_photos_sort(out bool sort_order, out int sort_by) { + Config.Facade.get_instance().get_library_photos_sort(out sort_order, out sort_by); + } + + protected override void set_config_photos_sort(bool sort_order, int sort_by) { + Config.Facade.get_instance().set_library_photos_sort(sort_order, sort_by); + } +} + diff --git a/src/folders/mk/folders.mk b/src/folders/mk/folders.mk new file mode 100644 index 0000000..d0023d7 --- /dev/null +++ b/src/folders/mk/folders.mk @@ -0,0 +1,31 @@ + +# UNIT_NAME is the Vala namespace. A file named UNIT_NAME.vala must be in this directory with +# a init() and terminate() function declared in the namespace. +UNIT_NAME := Folders + +# UNIT_DIR should match the subdirectory the files are located in. Generally UNIT_NAME in all +# lowercase. The name of this file should be UNIT_DIR.mk. +UNIT_DIR := folders + +# All Vala files in the unit should be listed here with no subdirectory prefix. +# +# NOTE: Do *not* include the unit's master file, i.e. UNIT_NAME.vala. +UNIT_FILES := \ + Branch.vala \ + Page.vala + +# Any unit this unit relies upon (and should be initialized before it's initialized) should +# be listed here using its Vala namespace. +# +# NOTE: All units are assumed to rely upon the unit-unit. Do not include that here. +UNIT_USES := \ + Sidebar \ + Photos + +# List any additional files that are used in the build process as a part of this unit that should +# be packaged in the tarball. File names should be relative to the unit's home directory. +UNIT_RC := + +# unitize.mk must be called at the end of each UNIT_DIR.mk file. +include unitize.mk + -- cgit v1.2.3