Commits

Iñigo Serna  committed d31c195

navigator: implemented view_file action, added splash dialog, decide installation path at compile, allow vfolder in cli, clean code

  • Participants
  • Parent commits c741397

Comments (0)

Files changed (5)

File irex/irexplus.vala

 // Copyright (C) 2011  Iñigo Serna <inigoserna@gmail.com>
 // Released under GPL v3+
 //
-// Time-stamp: <2011-09-05 11:07:48 inigo>
+// Time-stamp: <2011-09-09 19:16:10 inigo>
 //////////////////////////////////////////////////////////////////////
 
 
                                            out uint8[] png_m) throws IrexPlusError {
             GLib.Value v1 = file_id;
             _build_query(STMT_GET_THUMBS, v1);
-            if ((rc=stmt.step()) == Sqlite.DONE)
+            if ((rc=stmt.step()) == Sqlite.DONE) {
+                png_s = null;
+                png_m = null;
                 return;
-            else if (rc == Sqlite.ROW) {
+            } else if (rc == Sqlite.ROW) {
                 unowned uint8[] data_s = (uint8[]) stmt.column_blob(0);
                 data_s.length = stmt.column_bytes(0);
                 png_s = data_s;
             uint8[] png_s = new uint8[100000];
             uint8[] png_m = new uint8[100000];
             get_png_thumbs_from_db(file_id, out png_s, out png_m);
-            if (png_s != null)
-                cover_s = imgdata2pixbuf(png_s);
-            if (png_m != null)
-                cover_m = imgdata2pixbuf(png_m);
+            cover_s = (png_s==null) ? null : imgdata2pixbuf(png_s);
+            cover_m = (png_m==null) ? null : imgdata2pixbuf(png_m);
         }
 
         public void get_png_thumbs_from_fs(int file_id, out uint8[] png_s,
                 FileUtils.get_data(file_png_s, out png_s);
                 var file_png_m = coverfile_fmt.printf("medium", file_id%256, file_id);
                 FileUtils.get_data(file_png_m, out png_m);
-            } catch (GLib.Error e) {}
+            } catch (GLib.Error e) {
+                png_s = null;
+                png_m = null;
+            }
 
         }
 
                 cover_s = new Gdk.Pixbuf.from_file(file_png_s);
                 var file_png_m = coverfile_fmt.printf("medium", file_id%256, file_id);
                 cover_m = new Gdk.Pixbuf.from_file(file_png_m);
-            } catch (GLib.Error e) {}
+            } catch (GLib.Error e) {
+                cover_s = null;
+                cover_m = null;
+            }
 
         }
 

File navigator/AppResources.vala

+namespace AppResources {
+
+static const string img_quit[] = {
+"32 31 39 1",
+" 	c None",
+".	c #000000",
+"+	c #040404",
+"@	c #010101",
+"#	c #FFFFFF",
+"$	c #A7A7A7",
+"%	c #626262",
+"&	c #686868",
+"*	c #FEFEFE",
+"=	c #D8D8D8",
+"-	c #585858",
+";	c #616161",
+">	c #A9A9A9",
+",	c #575757",
+"'	c #666666",
+")	c #7C7C7C",
+"!	c #DCDCDC",
+"~	c #6F6F6F",
+"{	c #FDFDFD",
+"]	c #F3F3F3",
+"^	c #A4A4A4",
+"/	c #B5B5B5",
+"(	c #4E4E4E",
+"_	c #E0E0E0",
+":	c #6E6E6E",
+"<	c #D5D5D5",
+"[	c #808080",
+"}	c #9E9E9E",
+"|	c #C9C9C9",
+"1	c #505050",
+"2	c #EBEBEB",
+"3	c #6C6C6C",
+"4	c #B6B6B6",
+"5	c #CECECE",
+"6	c #8D8D8D",
+"7	c #747474",
+"8	c #C3C3C3",
+"9	c #757575",
+"0	c #EFEFEF",
+"................................",
+"................................",
+"................................",
+"................................",
+".....+++...............+++@.....",
+".....###$.............%###&.....",
+".....##*#=...........-#*##;.....",
+".....#*###>.........,#*###'.....",
+".....)###*#!.......~#*##{]......",
+"......^#*###/.....(#*###_.......",
+".......:###*#<...[#*##{_@.......",
+"........}#*##*|.1#####2.........",
+".........3#####4#*##*5..........",
+"..........6#*#####*#]...........",
+"...........7#*#####8.@..........",
+"............9#####0.............",
+"...........7#*#####8.@..........",
+"..........6#*#####*#]...........",
+".........3#####4#*##*5..........",
+"........}#*##*|.1#####2.........",
+".......:###*#<...[#*##{_@.......",
+"......^#*###/.....(#*###_.......",
+".....)###*#!.......~#*##{]......",
+".....#*###>.........,#*###'.....",
+".....##*#=...........-#*##;.....",
+".....###$.............%###&.....",
+".....+++...............+++@.....",
+"................................",
+"................................",
+"................................",
+"................................"};
+
+}

File navigator/Makefile

 TARGET = navigator
-SRC = navigator.vala ../irex/irex.vala ../irex/irexplus.vala
+SRC = navigator.vala AppResources.vala ../irex/irex.vala ../irex/irexplus.vala
+#INSTALL_ON_SYSTEM = -D INSTALL_ON_SYSTEM
 
 VALACPKGS = --pkg=gtk+-2.0 --pkg=gdk-x11-2.0 --pkg=gconf-2.0 --pkg=liberipc --pkg=posix --pkg=sqlite3 --pkg=MyUtils
 VALACC = arm-poky-linux-gnueabi-gcc
-VALACOPTS = --vapidir=../irex $(VALACPKGS) --cc=$(VALACC) $(patsubst %,-X %,$(CFLAGS))  --enable-experimental #--disable-warnings
+VALACOPTS = $(INSTALL_ON_SYSTEM) --vapidir=../irex $(VALACPKGS) --cc=$(VALACC) $(patsubst %,-X %,$(CFLAGS))  --enable-experimental #--disable-warnings
 #VALACOPTS += --save-temps
 STRIP = arm-poky-linux-gnueabi-strip -s
 

File navigator/README

 =========
 Author: Iñigo Serna <inigoserna@gmail.com>
 Version: 4
-Last update: Sun Sep  4 15:46:56 2011
+Last update: Mon Sep  5 22:05:05 2011
 
 
 Summary
   - Close
   - Actions:
     . View/Edit metadata
-    . Update metadata from file (not implemented yet)
+    . Bulk edit metadata (not implemented yet)
     . Delete file(s)
     . Mark as unread
     . Create shortcut
+    . Open with text viewer
     . Open containing folder, only for virtual folders
   - Virtual folders:
     . Shortcuts, same as in DR1000 or DR800+
 TODO
 ----
 . viewedit:
-  . remove cover
-  . update from file contents
-  . tags editing not implemented yet -> waiting for CTB and DB changes
-. view/edit bulk: <different among>, <from filename>, text
+  . tags editing not implemented yet -> waiting for DR800+ enhancements
+  . remove cover?
 . update docs
+  . workflow
+  . differences viewedit / bulk_edit
+  . NOTE: opening books in UDS will change metadata
 
 * Todo:
   - write a selection dialog: mark all, none, by extension, except extension
   - actions:
-    . edit metadata: title, author, tags, cover (?)
-    . update metadata and thumbnail with book contents, add files to global.db first if new
+    . rename file -> update global.db
+    . bulk edit metadata
   - search: by folder/filename, or by metadata -> virtual folder
   - tags-based browsing
   - ui for preferences

File navigator/navigator.vala

 // Copyright (C) 2011  Iñigo Serna <inigoserna@gmail.com>
 // Released under GPL v3+
 //
-// Time-stamp: <2011-09-05 19:41:52 inigo>
+// Time-stamp: <2011-09-10 12:05:23 inigo>
 //////////////////////////////////////////////////////////////////////
 
 
 using irex;
 using irexplus;
 using MyUtils;
+using AppResources;
 
 
 //////////////////////////////////////////////////////////////////////
 ///// Global constants and variables
 const string SDCARD = "/media/mmcblk0p1";
+#if INSTALL_ON_SYSTEM
+const string NAVIGATOR_HOME = "/usr/share/navigator";
+#else
+const string NAVIGATOR_HOME = SDCARD + "/Programs/_navigator";
+#endif
 const int KEY_UP       = 65362;
 const int KEY_PAGEUP   = 65365;
 const int KEY_DOWN     = 65364;
         db.get_pixbuf_thumbs(file_id, null, out cover_pb);
     } catch (IrexPlusError e) {
         GLib.stderr.printf("Error: can't retrieve thumb for entry %d: %s\n", file_id, e.message);
+        cover_pb = null;
     }
 }
 
 }
 
 
+
+//////////////////////////////////////////////////////////////////////
+///// Splash dialoh
+class SplashWin : Gtk.Window {
+
+    public SplashWin(Gtk.Window parent, string text) {
+        GLib.Object(type: Gtk.WindowType.POPUP);
+        this.set_modal(true);
+        this.set_transient_for(parent);
+        this.window_position = Gtk.WindowPosition.CENTER_ON_PARENT;
+        this.set_border_width(25);
+        this.decorated = false;
+        this.resizable = false;
+        var color = Gdk.Color();
+        Gdk.Color.parse("grey60", out color);
+        this.modify_bg(StateType.NORMAL, color);
+        var label = new Gtk.Label("");
+        label.set_markup("<span size='x-large' weight='bold'>%s</span>".printf(text));
+        this.add(label);
+        this.show_all();
+        while (Gtk.events_pending())
+            Gtk.main_iteration();
+    }
+
+    public void elliminate() {
+        hide_all();
+        destroy();
+    }
+}
+
+
 //////////////////////////////////////////////////////////////////////
 ///// PathLabel
 class Chunk {
     public bool set_path(owned string newpath) {
         if (!newpath.has_prefix("#") && !newpath.has_prefix(SDCARD))
             return false;
-        if (newpath.has_prefix("#")) {
-            if (newpath == "#lastopened")
-                _path = "SDCARD/# Recently opened #";
-            else if (newpath == "#lastadded")
-                _path = "SDCARD/# Recently added #";
-            else if (newpath == "#shortcuts")
-                _path = "SDCARD/# Shortcuts #";
-            else
-                _path = "SDCARD/# Unknown #";
-        } else {
+        if (newpath.has_prefix("#"))
+            _path = app.explode_vfolder_path(newpath);
+        else
             _path = normalize_path(newpath).replace(SDCARD, "SDCARD");
-        }
         chunks.build(_path);
         label.set_markup("<span %s>%s</span>".printf(txt_attrs, Markup.escape_text(_path)));
         return true;
     const string TMPL_HEADER1 = "<span size='medium' weight='bold'>[%d]</span>  <span size='small' weight='bold'>%s</span>";
     const string TMPL_HEADER2 = "<span size='small' weight='bold'>%s</span>";
     const string TMPL_DATA0   = "\n\nNo file\n\n";
-    const string TMPL_DATA1   = "<span weight='bold'>Title:\t</span>%s\n<span weight='bold'>Author:\t</span>%s\n<span weight='bold'>Type:\t</span>%s\n<span weight='bold'>Tags:\t</span>%s\n<span weight='bold'>Opened:\t</span>%s";
+    const string TMPL_DATA1   = "<b>Title:\t</b>%s\n<b>Author:\t</b>%s\n<b>Tags:\t</b>%s\n<b>Type:\t</b>%s\n<b>Opened:\t</b>%s";
 
     // variables
     Gtk.Label   header;
             header.label = TMPL_HEADER1.printf(book.id, Markup.escape_text(fullpath));
             info.label = TMPL_DATA1.printf(Markup.escape_text(book.title),
                                            Markup.escape_text(book.author),
+                                           Markup.escape_text(book.tags),
                                            Markup.escape_text(book.description),
-                                           Markup.escape_text(book.tags),
                                            Markup.escape_text(book.lastread==0 ? "never" : secs2strftime(book.lastread, "%d/%m/%Y %H:%M")));
         }
         cover.set_from_pixbuf(get_cover(book));
     }
 
     public void display(string dir) {
-        lbl_dir.label = "Current folder is: <i>'%s'</i>".printf(Markup.escape_text(dir.replace(SDCARD, "SDCARD")));
+        var path = dir.has_prefix("#") ? app.explode_vfolder_path(dir) : dir.replace(SDCARD, "SDCARD");
+        lbl_dir.label = "Current folder is: <i>'%s'</i>".printf(Markup.escape_text(path));
         btn_close.grab_focus();
         show_all();
     }
 
 
 //////////////////////////////////////////////////////////////////////
-///// HelpWin
-class HelpWin : Gtk.Window {
-    Gtk.Button btn_close;
+///// ViewWin
+class ViewFileWin : Gtk.Window {
+    Gtk.Label    lbl_title;
+    Gtk.TextView tv;
 
-    public HelpWin(Navigator app) {
+    public ViewFileWin(Navigator app) {
         this.set_modal(true);
         this.set_transient_for(app);
         this.set_events(Gdk.EventMask.FOCUS_CHANGE_MASK);
-        this.focus_out_event.connect(() => {
-                this.hide_all();
-                return false;
-            });
-        this.title = "Navigator Help";
+        this.focus_out_event.connect(() => { this.hide_all(); return false; });
         this.set_border_width(20);
         var vbox = new Gtk.VBox(false, 10);
         this.add(vbox);
-        var lbl_title = new Gtk.Label("");
-        // lbl_title.xalign = 0;
-        lbl_title.set_markup("<span size='x-large' weight='bold'>Navigator Help</span>");
-        vbox.pack_start(lbl_title, false, false, 10);
+        var hbox = new Gtk.HBox(false, 10);
+        vbox.pack_start(hbox, false, false, 10);
+        lbl_title = new Gtk.Label("");
+        lbl_title.ellipsize = EllipsizeMode.END;
+        hbox.pack_start(lbl_title, true, true, 0);
+        var evbox_quit = new Gtk.EventBox();
+        evbox_quit.set_events(EventMask.BUTTON_PRESS_MASK);
+        evbox_quit.button_press_event.connect((evbox) => { this.hide_all(); return false; });
+        var img = new Gtk.Image.from_pixbuf(new Gdk.Pixbuf.from_xpm_data(AppResources.img_quit));
+        evbox_quit.add(img);
+        hbox.pack_end(evbox_quit, false, false, 0);
         vbox.pack_start(new Gtk.HSeparator(), false, false, 10);
-        string contents;
-        var file_readme = Path.build_filename(SDCARD, "Programs/_navigator/README");
-        try {
-            FileUtils.get_contents(file_readme, out contents);
-        } catch (GLib.Error e) {
-            GLib.stderr.printf("Error: can't load README file %s\n", e.message);
-            contents = "ERROR: can't load README file";
-        }
         var scrollwin = new Gtk.ScrolledWindow(null, null);
-        scrollwin.set("hscrollbar-policy", Gtk.PolicyType.NEVER,
+        scrollwin.set("hscrollbar-policy", Gtk.PolicyType.AUTOMATIC,
                       "vscrollbar-policy", Gtk.PolicyType.AUTOMATIC,
                       "shadow-type", Gtk.ShadowType.NONE);
-        var tv = new Gtk.TextView();
+        tv = new Gtk.TextView();
         tv.set("editable", false, "cursor-visible", false,
                // "wrap-mode", Gtk.WrapMode.CHAR,
                "left-margin", 0, "right-margin", 0);
-        tv.buffer.set_text(contents, -1);
+        tv.can_focus = false;
         scrollwin.add(tv);
         vbox.pack_start(scrollwin, true, true, 10);
-        vbox.pack_start(new Gtk.HSeparator(), false, false, 10);
-        this.btn_close = new Gtk.Button.from_stock("gtk-close");
-        this.btn_close.clicked.connect(() => { this.hide_all(); });
-        vbox.pack_start(this.btn_close, false, false, 0);
     }
 
-    public void display() {
-        btn_close.grab_focus();
+    public void display (string filename, string title="") {
+        var header = (title=="") ? Path.get_basename(filename) : title;
+        this.title = header;
+        lbl_title.set_markup("<span size='xx-large' weight='bold'>%s</span>".printf(header));
+        string contents;
+        try {
+            FileUtils.get_contents(filename, out contents);
+        } catch (GLib.Error e) {
+            GLib.stderr.printf("Error: can't load file '%s': %s\n", filename, e.message);
+            contents = "ERROR: can't load file";
+        }
+        this.tv.buffer.set_text(contents, -1);
         show_all();
     }
 }
         lbl_text.set_markup("""Here you can edit <i>title</i>, <i>author</i> or <i>tags</i> fields and view other metadata.
 Pressing the button next to <i>title</i> will fill with the file name, without the extension.
 Pressing the button next to <i>author</i> will fill with the folder name.
-The two arrows at the bottom left allow for easy and fast selection of folder items.
+You can use the bar or the arrows at bottom left for fast selection of folder items.
 
 Remember to click on <b>Save</b> button before closing this window or changing item.""");
         lbl_text.xalign = 0;
     LastreadWin       win_lastread;
     LastfoldersWin    win_lastfolders;
     ViewEditWin       win_viewedit;
-    HelpWin           win_help;
+    ViewFileWin       win_viewfile;
     Gtk.MessageDialog dlg_error;
     Gtk.MessageDialog dlg_question;
 
         btn_lastfolders.clicked.connect(cb_lastfolders_clicked);
         btn_lastfolders.can_focus = false;
         btn_lastfolders.relief = ReliefStyle.NONE;
-        btn_lastfolders.set_image(new Gtk.Image.from_file("/media/mmcblk0p1/Programs/_navigator/icons/tb_lastfolders.png"));
+        btn_lastfolders.set_image(new Gtk.Image.from_file(NAVIGATOR_HOME+"/icons/tb_lastfolders.png"));
         hbox.pack_end(btn_lastfolders, false, false, 0);
         var btn_lastread = new Gtk.Button();
         btn_lastread.clicked.connect(cb_lastread_clicked);
         btn_lastread.can_focus = false;
         btn_lastread.relief = ReliefStyle.NONE;
-        btn_lastread.set_image(new Gtk.Image.from_file("/media/mmcblk0p1/Programs/_navigator/icons/tb_lastread.png"));
+        btn_lastread.set_image(new Gtk.Image.from_file(NAVIGATOR_HOME+"/icons/tb_lastread.png"));
         hbox.pack_end(btn_lastread, false, false, 0);
         var btn_favs = new Gtk.Button();
         btn_favs.clicked.connect(cb_favs_clicked);
         btn_favs.can_focus = false;
         btn_favs.relief = ReliefStyle.NONE;
-        btn_favs.set_image(new Gtk.Image.from_file("/media/mmcblk0p1/Programs/_navigator/icons/tb_bookmarks.png"));
+        btn_favs.set_image(new Gtk.Image.from_file(NAVIGATOR_HOME+"/icons/tb_bookmarks.png"));
         hbox.pack_end(btn_favs, false, false, 0);
         hbox.show_all();
         vbox.pack_start(hbox, false, false, 10);
         // menu
         menu_main = new irex.Menu(menu_manager, "menumain", "Navigator");
         var group_main = menu_main.addGroup("groupmain", "Main Buttons");
-        group_main.addItem("showdetails", "Show details", "/media/mmcblk0p1/Programs/_navigator/icons/nav_details.png");
-        group_main.addItem("showhidden",  "Show hidden",  "/media/mmcblk0p1/Programs/_navigator/icons/nav_hidden.png");
+        group_main.addItem("showdetails", "Show details", NAVIGATOR_HOME+"/icons/nav_details.png");
+        group_main.addItem("showhidden",  "Show hidden",  NAVIGATOR_HOME+"/icons/nav_hidden.png");
         group_main.addItem("fullscreen",  "Fullscreen",   "mode_full_screen");
         group_main.addItem("help",        "Help",         "dictionary_lookup");
-        group_main.addItem("close",       "Close",        "/media/mmcblk0p1/Programs/_navigator/icons/nav_close.png");
+        group_main.addItem("close",       "Close",        NAVIGATOR_HOME+"/icons/nav_close.png");
         var subgroup_actions0 = group_main.addSubGroup("groupactions0", "Actions");
         var subgroup_actions = subgroup_actions0.addSubGroup("groupactions", "Actions");
-        subgroup_actions.addItem("vieweditmetadata", "View/Edit metadata",        "rename");
-        subgroup_actions.addItem("updatemetadata",   "Update metadata from file", "reload");
-        subgroup_actions.addItem("deletefiles",      "Delete file(s)",            "delete");
-        subgroup_actions.addItem("unsetlastread",    "Mark as unread",            "cancel");
-        subgroup_actions.addItem("createshortcut",   "Create shortcut",           "bookmark");
-        subgroup_actions.addItem("openfolder",       "Open containing folder",    "/usr/share/ctb/icon-folder-mini.png");
+        subgroup_actions.addItem("vieweditmetadata", "View/Edit metadata",     "rename");
+        subgroup_actions.addItem("bulkeditmetadata", "Bulk edit metadata",     "tools_character");
+        subgroup_actions.addItem("deletefiles",      "Delete file(s)",         "delete");
+        subgroup_actions.addItem("unsetlastread",    "Mark as unread",         "cancel");
+        subgroup_actions.addItem("createshortcut",   "Create shortcut",        "bookmark");
+        subgroup_actions.addItem("viewfile",         "Open with text viewer",  "/usr/share/ctb/icon-note-mini.png");
+        subgroup_actions.addItem("openfolder",       "Open containing folder", "/usr/share/ctb/icon-folder-mini.png");
         var subgroup_places0 = group_main.addSubGroup("groupplaces0", "Virtual folders");
         var subgroup_places = subgroup_places0.addSubGroup("groupplaces", "Virtual folders");
-        subgroup_places.addItem("shortcuts",  "Shortcuts",       "/media/mmcblk0p1/Programs/_navigator/icons/tb_bookmarks.png");
-        subgroup_places.addItem("lastadded",  "Recently added",  "/media/mmcblk0p1/Programs/_navigator/icons/tb_lastfolders.png");
-        subgroup_places.addItem("lastopened", "Recently opened", "/media/mmcblk0p1/Programs/_navigator/icons/tb_lastread.png");
+        subgroup_places.addItem("shortcuts",  "Shortcuts",       NAVIGATOR_HOME+"/icons/tb_bookmarks.png");
+        subgroup_places.addItem("lastadded",  "Recently added",  NAVIGATOR_HOME+"/icons/tb_lastfolders.png");
+        subgroup_places.addItem("lastopened", "Recently opened", NAVIGATOR_HOME+"/icons/tb_lastread.png");
         menu_main.realise();
         menu_main.show();
         // toolbar
                 dbox.show_or_hide();
             }
         } else if (group=="Navigator_groupactions") {
-            if (item=="deletefiles")
+            if (item=="vieweditmetadata")
+                viewedit_metadata();
+            else if (item=="bulkeditmetadata")
+                return;
+            else if (item=="deletefiles")
                 delete_files();
-            else if (item=="vieweditmetadata")
-                viewedit_metadata();
-            else if (item=="updatemetadata")
-                return;
             else if (item=="unsetlastread")
                 unset_lastread();
             else if (item=="createshortcut")
                 create_shortcut();
             else if (item=="openfolder")
                 open_folder();
+            else if (item=="viewfile")
+                view_file();
         } else if (group=="Navigator_groupplaces") {
             if (item=="shortcuts")
                 init_path("#shortcuts");
 
 
     private void on_show_help() {
-        if (win_help == null)
-            win_help = new HelpWin(this);
-        win_help.display();
+        if (win_viewfile == null)
+            win_viewfile = new ViewFileWin(this);
+        win_viewfile.display(NAVIGATOR_HOME+"/README", "Navigator Help");
     }
 
 
     }
 
 
-    private void init_path(string newpath) {
-        if (newpath.has_prefix("#")) { // vfolders
-            if (newpath == SDCARD+"/# Recently opened #")
-                newpath = "#lastopened";
-            else if (newpath == SDCARD+"/# Recently added #")
-                newpath = "#lastadded";
-            else if (newpath == SDCARD+"/# Shortcuts #")
-                newpath = "#shortcuts";
+    public string explode_vfolder_path(string path) {
+        if (path == "#lastopened")
+            return "SDCARD/# Recently opened #";
+        else if (path == "#lastadded")
+            return "SDCARD/# Recently added #";
+        else if (path == "#shortcuts")
+            return "SDCARD/# Shortcuts #";
+        else
+            return path;
+    }
+
+
+    public string implode_vfolder_path(string path) {
+        if (path == SDCARD+"/# Recently opened #")
+            return "#lastopened";
+        else if (path == SDCARD+"/# Recently added #")
+            return "#lastadded";
+        else if (path == SDCARD+"/# Shortcuts #")
+            return "#shortcuts";
+        else
+            return path;
+    }
+
+
+    private void init_path(owned string newpath) {
+        if (newpath.has_prefix("#") || newpath.has_prefix(SDCARD+"/#")) { // vfolders
+            newpath = implode_vfolder_path(newpath);
             menu_manager.set_item_state("openfolder", "Navigator_groupactions", "normal");
         } else { // normal file system folders
             if (!FileUtils.test(newpath, FileTest.IS_DIR)) {
             win_lastfolders.hide_all();
         if (win_viewedit != null)
             win_viewedit.hide_all();
-        if (win_help != null)
-            win_help.hide_all();
+        if (win_viewfile != null)
+            win_viewfile.hide_all();
         selection = false;
         var i = 0;
         foreach(string d in lastfolders) {
                          "ERROR: %s".printf(err);
             dlg_error_run(errmsg);
         }
+        var splash = new SplashWin(app, "Updating database\n\n     Please wait...");
         update_globaldb();
+        splash.elliminate();
         init_path(dir);
     }
 
     }
 
 
+    private void view_file() {
+        var f = get_current_file();
+        if (f.isdir)
+            return;
+        if (win_viewfile == null)
+            win_viewfile = new ViewFileWin(this);
+        win_viewfile.display(Path.build_filename(f.dir, f.name));
+    }
+
+
     ///// main methods
     public void on_change_path(owned string newpath) {
         newpath = newpath.replace("SDCARD", SDCARD);
         string? initialpath = null;
         if (args.length>1 && FileUtils.test(args[1], FileTest.IS_DIR))
             initialpath = args[1];
-        else if (FileUtils.test(cfg.bookmarks[0], FileTest.IS_DIR))
+        else if (FileUtils.test(cfg.bookmarks[0], FileTest.IS_DIR) ||
+                 cfg.bookmarks[0].has_prefix("#") ||
+                 cfg.bookmarks[0].has_prefix(SDCARD+"/#"))
             initialpath = cfg.bookmarks[0];
         else
             initialpath = SDCARD;