Merge lp:~donadigo/pantheon-files/filechooser-module into lp:~elementary-apps/pantheon-files/trunk

Proposed by Adam Bieńkowski on 2015-05-03
Status: Merged
Merged at revision: 1842
Proposed branch: lp:~donadigo/pantheon-files/filechooser-module
Merge into: lp:~elementary-apps/pantheon-files/trunk
Diff against target: 700 lines (+646/-2)
6 files modified
CMakeLists.txt (+6/-2)
INSTALL (+3/-0)
filechooser-module/CMakeLists.txt (+29/-0)
filechooser-module/FileChooserDialog.vala (+271/-0)
filechooser-module/LocationBarChooser.vala (+280/-0)
filechooser-module/Plugin.vala (+57/-0)
To merge this branch: bzr merge lp:~donadigo/pantheon-files/filechooser-module
Reviewer Review Type Date Requested Status
Jeremy Wootten Approve on 2015-05-31
Fabio Zaramella Needs Information on 2015-05-09
Daniel Fore ux 2015-05-03 Approve on 2015-05-06
elementary Apps team code 2015-05-06 Pending
Review via email: mp+258133@code.launchpad.net

Description of the change

An elementary-styled filechooser modified dialog. It will be modified only if the pantheon-files will be the default file manager. The breadcrumbs code is taken and patched from original Files.

Test it with: GTK_MODULES=pantheon-filechooser-module app-cmd,
e.g: GTK_MODULES=pantheon-filechooser-module scratch-text-editor

The "catch dialog" method is written by tintou and is available here:
https://code.launchpad.net/~tintou/pantheon-files/gtk-module

To post a comment you must log in.
Rico Tzschichholz (ricotz) wrote :

Use "if (Gtk.check_version (3, 14, 0) == null) {...}"

Rico Tzschichholz (ricotz) wrote :

Don't touch po/* that way

Daniel Fore (danrabbit) wrote :

It looks like the "back" button doesn't actually go back. It goes "up". Open the dialog, notice that "back" is immediately sensitive. This shouldn't be the case as there is no navigation history. This should either be made into an actual back button (as in Files) or removed since the "up" functionality is already provided in the breadcrumb.

There seems to be a Gtk.ActionBar called "extra_and_filters" above the dialog action box. Is this actionbar necessary? Can it be removed? It causes a weird white area and double border in the open file dialog.

It seems that the new folder item should be present in the Save File dialog and not the Open Folder dialog.

review: Needs Fixing
Daniel Fore (danrabbit) wrote :

Back and forward buttons are sensitive with no history in the Save as dialog which causes a segfault when clicked.

We've still got a double border issue in the action area. We're duplicated each other somewhere :p It's fine in Save As, but there's a double border in the Open File and Open Folder. Might want to make sure you've got lp:egtk trunk since I have made some small adjustments for this dialog.

Are we able to affect the places sidebar at all? Specifically it shows a "desktop" folder even though one doesn't exist. Also we'd probably want to remove the "enter location" item since the pathbar widget handles that.

In the "Save As" dialog, is it possible to move the name entry down into the action-box? There's a lot of free space in the middle there and it would save us that whole vertical area.

Daniel Fore (danrabbit) wrote :

Just noticed that the text input version of the pathbar doesn't actually navigate there :p

Aneurin Hall (aneurin-hall) wrote :

will this finally bring in icon view and scaling?

Daniel Fore (danrabbit) wrote :

Works fantastic now. Don't really have anything to complain about that isn't a wishlist item ;D

Thank Adam! UX Approve :)

review: Approve (ux)
Fabio Zaramella (fabiozaramella) wrote :

When i start it with an option that provides a path it doesn't open that path. e.g. In Music choosing "Change music folder" it doesn't bring up the dialog with the music folder opened.

review: Needs Information
Adam Bieńkowski (donadigo) wrote :

Fabio Zaramella: I think it is fixed now. You can check it by testing the newest commit.

Jeremy Wootten (jeremywootten) wrote :

(1) On compiling the following warning was given:

"Access to static member `CustomFileChooserDialog.chooser' with an instance reference:
     dialog_new.chooser.set_current_folder dialog.get_current_folder ());"

(2) Both Scratch and Audience gave the same error message:

"[_LOG_LEVEL_FATAL 12:39:37.465513] gee_array_list_real_slice: assertion '_tmp3_ <= _tmp4_' failed"

when changing the directory with the pathbar while opening a file. Not sure whether it is due to this branch tho'.

(3) The variable MOULDES_LIBDIR is presumably a mispelling of MODULES_LIBDIR? or MODULE_LIBDIR? It occurs in diff lines 228 and 250.

(4) Is it necessary to duplicate code and filenames in the filechooser-module directory? There are now three files named LocationBar.vala two of which duplicate code. The filechooser-module/AbstractLocationBar.vala duplicates code from /libwidgets/LocationBar.vala. filechooser-module/BreadcrumbsElements.vala duplicates code from libwidgets/BreadcrumbsElements. If this can be avoided it would make maintenance easier.

(5) diff lines 379 & following are indented 8 spaces instead of 4.

(6) Try to avoid wrapping caused by too long lines by vertically aligning parameters (e.g. diff lines 106, 167,168,290,292) (some of these may have been pre-existing in the code duplicated). Elementary code style gives a hard maximum line length of 120 characters, preferably not more than 80.

(7) The deep nesting in remove_gtk_widgets should be avoided if possible. Above 4 or 5 levels becomes hard to follow and the lines become too long.

(8) Please remove the tabs in FileChooserDialog.vala - all indents should be spaces.

(9) The "Create folder" button needs a tooltip.

(10) Formatting of diff lines 897-899 looks odd.

(11) If you change directory with the pathbar then you have to click the back button twice before the directory changes back.

I note that the problem of variable filechooser dialogs is not completely solved by this branch - for example LibreOffice and Geany still show different filechoosers.

review: Needs Fixing
Adam Bieńkowski (donadigo) wrote :

Jeremy: you can look at the newest commit. I tested it a little bit and the gee_array_list_real_slice doesn't seem to appear anymore. The eleventh point still needs to be fixed.

Daniel Fore (danrabbit) wrote :

Regarding Geany and LibreOffice, I'm pretty sure they're both using the Gtk2 file chooser (to which list we can add Chrome and a few others). I'm not sure there's anything we can do here. They'd have to call the Gtk3 chooser.

Jeremy Wootten (jeremywootten) wrote :

The functionality and compile errors are now fixed - thanks.

There is more that could be done to eliminate duplicated code but I think that is best left to a separate future branch as it would conflict with other merge proposals affecting the pathbar.

The formatting is improved but there are still some issues:
1) FileChooseDialog.vala contains tabs. I advise you view your code in a text editor that displays tabs as an arrow so you can spot them easily.
2) FileChooserDialog.vala has misaligned braces in remove_gtk_widgets (), perhaps due to trying to reduce line length. I suggest that you move the bodies of the more deeply indented foreach blocks into separate functions to reduce line length and improve clarity. e.g.

 if (w1.get_name () == GTK_PATHBAR_PATH[1])
     remove_gtkpathbar1_children (w1);

3) GTK_FILTERCHOSSER_PATH is a mispelling of GTK_FILTERCHOOSER_PATH

4) There are files added to po/. These should be removed (bzr remove po/af.po etc) if they are not in trunk.

review: Needs Fixing
1838. By Adam Bieńkowski on 2015-05-18

FileChooserDialog.vala now does not contain any tabs; split remove_gtk_widgets to different methods; fixed mispelling of GTK_FILTERCHOOSER_PATH; removed unneded po files

Adam Bieńkowski (donadigo) wrote :

Jeremy: I think the tabs should gone now. I converted the tabs to spaces from Sublime Text. I splitted remove_gtk_widgets method to 3 methods named: transform_x_container. The po files are also gone now + GTK_FILTERCHOOSER_PATH variable name is fixed.

1839. By Adam Bieńkowski on 2015-05-30

Fixed: wrong button response id caused not showing filter menu in some cases

Jeremy Wootten (jeremywootten) wrote :

There are misaligned method parameters in LocationBarChooser.vala, but as these were copied from existing code it should not block this branch.

Otherwise, all is good - thanks.

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'CMakeLists.txt'
2--- CMakeLists.txt 2015-05-16 11:43:17 +0000
3+++ CMakeLists.txt 2015-05-30 21:14:32 +0000
4@@ -19,13 +19,16 @@
5 add_definitions ("-w")
6
7 option (LIB_ONLY "Build libcore and libwidgets only" FALSE)
8+option (MODULE_ONLY "Build only custom gtk filechooser dialog module" FALSE)
9
10 find_package (Vala REQUIRED)
11 include (ValaVersion)
12 ensure_vala_version ("0.26" MINIMUM)
13 include (ValaPrecompile)
14
15-IF (LIB_ONLY)
16+if (MODULE_ONLY)
17+ add_subdirectory (filechooser-module)
18+ELSEIF (LIB_ONLY)
19 add_subdirectory (libcore)
20 add_subdirectory (libwidgets)
21 ELSE ()
22@@ -35,5 +38,6 @@
23 add_subdirectory (libcore)
24 add_subdirectory (libwidgets)
25 add_subdirectory (plugins)
26+ add_subdirectory (filechooser-module)
27 add_subdirectory (po)
28-ENDIF (LIB_ONLY)
29+ENDIF ()
30
31=== modified file 'INSTALL'
32--- INSTALL 2014-07-28 01:14:13 +0000
33+++ INSTALL 2015-05-30 21:14:32 +0000
34@@ -39,3 +39,6 @@
35
36 To install only libcore and libwidgets use the following command:
37 cmake .. -DLIB_ONLY=true
38+
39+ To install only the Gtk-Module use the following command:
40+ cmake .. -DMODULE_ONLY=true
41
42=== added directory 'filechooser-module'
43=== added file 'filechooser-module/CMakeLists.txt'
44--- filechooser-module/CMakeLists.txt 1970-01-01 00:00:00 +0000
45+++ filechooser-module/CMakeLists.txt 2015-05-30 21:14:32 +0000
46@@ -0,0 +1,29 @@
47+find_package (PkgConfig)
48+
49+pkg_check_modules (DEPS REQUIRED glib-2.0 gthread-2.0 gtk+-3.0>=3.10 granite gee-0.8)
50+add_definitions (${DEPS_CFLAGS})
51+link_directories (${DEPS_LIBRARY_DIRS})
52+set (MODULE_NAME "pantheon-filechooser-module")
53+set (MOULDE_LIBDIR "/usr/lib/x86_64-linux-gnu")
54+
55+vala_precompile (VALA_C ${MODULE_NAME}
56+ ${CMAKE_SOURCE_DIR}/libwidgets/LocationBar.vala
57+ ${CMAKE_SOURCE_DIR}/libwidgets/BreadcrumbsElements.vala
58+ LocationBarChooser.vala
59+ FileChooserDialog.vala
60+ Plugin.vala
61+PACKAGES
62+ gtk+-3.0
63+ granite
64+ posix
65+ gee-0.8
66+OPTIONS
67+ --thread
68+)
69+
70+link_libraries(${DEPS_LIBRARIES})
71+add_library (${MODULE_NAME} MODULE ${VALA_C})
72+target_link_libraries (${MODULE_NAME} ${DEPS_LIBRARIES} gthread-2.0)
73+
74+# Installation
75+install (TARGETS ${MODULE_NAME} DESTINATION "${MOULDE_LIBDIR}/gtk-3.0/modules/")
76
77=== added file 'filechooser-module/FileChooserDialog.vala'
78--- filechooser-module/FileChooserDialog.vala 1970-01-01 00:00:00 +0000
79+++ filechooser-module/FileChooserDialog.vala 2015-05-30 21:14:32 +0000
80@@ -0,0 +1,271 @@
81+/*-
82+ * Copyright (c) 2015 Pantheon Developers (http://launchpad.net/elementary)
83+ *
84+ * This library is free software; you can redistribute it and/or
85+ * modify it under the terms of the GNU Library General Public
86+ * License as published by the Free Software Foundation; either
87+ * version 2 of the License, or (at your option) any later version.
88+ *
89+ * This library is distributed in the hope that it will be useful,
90+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
91+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
92+ * Library General Public License for more details.
93+ *
94+ * You should have received a copy of the GNU Library General Public
95+ * License along with this library; if not, write to the
96+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
97+ * Boston, MA 02111-1307, USA.
98+ *
99+ * Authored by: Adam Bieńkowski <donadigos159@gmail.com>
100+ */
101+
102+public class CustomFileChooserDialog : Object {
103+ private static Gtk.FileChooser chooser;
104+
105+ private static Gtk.FileChooserDialog d;
106+ private static Gtk.Widget rootwidget;
107+
108+ private static Gtk.Box container_box;
109+ private static Gtk.Button? gtk_folder_button = null;
110+
111+ /* Response to get parent of the bottom box */
112+ private const int BUTTON_RESPONSE = -6;
113+
114+ /* Paths to widgets */
115+ private const string[] GTK_PATHBAR_PATH = { "widget", "browse_widgets_box", "browse_files_box", "browse_header_box" };
116+ private const string[] GTK_FILTERCHOOSER_PATH = { "extra_and_filters", "filter_combo_hbox" };
117+ private const string[] GTK_CREATEFOLDER_BUTTON_PATH = { "browse_header_stack", "browse_path_bar_hbox", "browse_new_folder_button" };
118+ private const string PLACES_SIDEBAR_PATH = "places_sidebar";
119+
120+ private const string FILE_PREFIX = "file://";
121+
122+ private GenericArray<string> forward_path_list = new GenericArray<string> ();
123+ private Gee.ArrayList<string> history = new Gee.ArrayList<string> ();
124+
125+ private static bool filters_available = false;
126+
127+ private static string open_path;
128+ private string previous_path = "";
129+
130+ public CustomFileChooserDialog (Gtk.FileChooserDialog _dialog) {
131+ /* The "d" variable is the main dialog */
132+ d = _dialog;
133+ d.can_focus = true;
134+
135+ /* Main FileChooser interface */
136+ chooser = (d as Gtk.FileChooser);
137+
138+ d.deletable = false;
139+ assign_container_box ();
140+ setup_filter_box ();
141+ remove_gtk_widgets ();
142+
143+ var header_bar = new Gtk.HeaderBar ();
144+
145+ var button_back = new Gtk.Button.from_icon_name ("go-previous-symbolic", Gtk.IconSize.LARGE_TOOLBAR);
146+ button_back.tooltip_text = _("Previous");
147+ button_back.sensitive = false;
148+
149+ var button_forward = new Gtk.Button.from_icon_name ("go-next-symbolic", Gtk.IconSize.LARGE_TOOLBAR);
150+ button_forward.tooltip_text = _("Next");
151+ button_forward.sensitive = false;
152+
153+ var pathbar = new Marlin.View.Chrome.LocationBar (rootwidget);
154+ pathbar.path = FILE_PREFIX + chooser.get_current_folder ();
155+ pathbar.hexpand = true;
156+
157+ header_bar.pack_start (button_back);
158+ header_bar.pack_start (button_forward);
159+ header_bar.pack_start (pathbar);
160+ if ((gtk_folder_button != null) && (chooser.get_action () != Gtk.FileChooserAction.OPEN)) {
161+ var create_folder_button = new Gtk.Button.from_icon_name ("folder-new", Gtk.IconSize.LARGE_TOOLBAR);
162+ create_folder_button.set_tooltip_text (_("Create folder"));
163+ create_folder_button.clicked.connect (() => {
164+ gtk_folder_button.clicked ();
165+ });
166+
167+ header_bar.pack_end (create_folder_button);
168+ }
169+
170+ d.set_titlebar (header_bar);
171+ d.show_all ();
172+
173+ button_back.clicked.connect (() => {
174+ forward_path_list.add (chooser.get_current_folder ());
175+
176+ history.remove (history.last ());
177+ chooser.set_current_folder (history.last ());
178+ history.remove (history.last ());
179+ });
180+
181+ button_forward.clicked.connect (() => {
182+ if (forward_path_list.length > 0) {
183+ int length = forward_path_list.length - 1;
184+
185+ pathbar.path = FILE_PREFIX + forward_path_list.@get (length);
186+ chooser.set_current_folder (forward_path_list.@get (length));
187+ forward_path_list.remove (forward_path_list.@get (length));
188+ }
189+ });
190+
191+ chooser.current_folder_changed.connect (() => {
192+ if (history.size > 0)
193+ previous_path = history.last ();
194+ else if (open_path != chooser.get_current_folder ()) {
195+ previous_path = "";
196+ history.add (open_path);
197+ }
198+
199+ button_back.sensitive = (history.size > 0);
200+ button_forward.sensitive = (forward_path_list.length > 0);
201+
202+ if (chooser.get_current_folder () != previous_path)
203+ history.add (chooser.get_current_folder ());
204+
205+ pathbar.path = FILE_PREFIX + chooser.get_current_folder ();
206+ });
207+
208+ pathbar.change_to_file.connect ((file) => {
209+ chooser.set_current_folder (file);
210+ });
211+ }
212+
213+ public void set_open_path (string _open_path) {
214+ open_path = _open_path;
215+ previous_path = open_path;
216+ chooser.set_current_folder (open_path);
217+ }
218+
219+ /* Remove GTK's native path bar and FileFilter chooser by widgets names */
220+ private static void remove_gtk_widgets () {
221+ foreach (var root in d.get_children ()) {
222+ foreach (var w0 in (root as Gtk.Container).get_children ()) {
223+ if (w0.get_name () == GTK_PATHBAR_PATH[0]) {
224+ /* Add top separator between headerbar and filechooser when is not Save action */
225+ var chooserwidget = w0 as Gtk.Container;
226+ chooserwidget.vexpand = true;
227+
228+ (root as Gtk.Container).remove (w0);
229+ var root_box = new Gtk.Box (Gtk.Orientation.VERTICAL, 0);
230+ root_box.add (new Gtk.Separator (Gtk.Orientation.HORIZONTAL));
231+ root_box.add (chooserwidget);
232+
233+ if (chooser.get_extra_widget () == null)
234+ root_box.add (new Gtk.Separator (Gtk.Orientation.HORIZONTAL));
235+
236+ (root as Gtk.Container).add (root_box);
237+ rootwidget = chooserwidget;
238+ rootwidget = w0;
239+ rootwidget.can_focus = true;
240+ transform_rootwidget_container (rootwidget, w0);
241+ }
242+ }
243+ }
244+ }
245+
246+ private static void transform_rootwidget_container (Gtk.Widget rootwidget, Gtk.Widget w0) {
247+ foreach (var w1 in (rootwidget as Gtk.Container).get_children ()) {
248+ if (w1.name == "GtkBox" && w1.get_name () != GTK_PATHBAR_PATH[1]) {
249+ var new_w1 = w1.@ref ();
250+ (rootwidget as Gtk.Container).remove (w1);
251+
252+ foreach (var grid in (new_w1 as Gtk.Container).get_children ()) {
253+ if (grid != null) {
254+ var new_grid = grid.@ref ();
255+ (new_grid as Gtk.Widget).margin = 0;
256+ (new_w1 as Gtk.Container).remove (grid);
257+ container_box.add (new_grid as Gtk.Widget);
258+ }
259+ }
260+
261+ container_box.show_all ();
262+ } else if (w1.get_name () == GTK_PATHBAR_PATH[1])
263+ transform_w1_container (w1);
264+ else {
265+ if (w1.get_name () == GTK_FILTERCHOOSER_PATH[0]) {
266+ /* Remove extra_and_filters if there is no extra widget */
267+ if (chooser.get_extra_widget () == null)
268+ (w0 as Gtk.Container).remove (w1);
269+ else {
270+ foreach (var w5 in (w1 as Gtk.Container).get_children ()) {
271+ if (w5.get_name () == GTK_FILTERCHOOSER_PATH[1])
272+ (w1 as Gtk.Container).remove (w5);
273+ }
274+ }
275+ }
276+ }
277+ }
278+ }
279+
280+ private static void transform_w1_container (Gtk.Widget w1) {
281+ foreach (var paned in (w1 as Gtk.Container).get_children ()) {
282+ foreach (var w2 in (paned as Gtk.Container).get_children ()) {
283+ if (w2.get_name () == PLACES_SIDEBAR_PATH) {
284+ (w2 as Gtk.PlacesSidebar).show_desktop = false;
285+ (w2 as Gtk.PlacesSidebar).show_enter_location = false;
286+ } else if (w2.get_name () == GTK_PATHBAR_PATH[2])
287+ transform_w2_container (w2);
288+ }
289+ }
290+ }
291+
292+ private static void transform_w2_container (Gtk.Widget w2) {
293+ foreach (var w3 in (w2 as Gtk.Container).get_children ()) {
294+ if (w3.get_name () == GTK_PATHBAR_PATH[3]) {
295+ foreach (var w4 in (w3 as Gtk.Container).get_children ()) {
296+ if (w4.get_name () == GTK_CREATEFOLDER_BUTTON_PATH[0]) {
297+ foreach (var w5 in (w4 as Gtk.Container).get_children ()) {
298+ if (w5.get_name () == GTK_CREATEFOLDER_BUTTON_PATH[1]) {
299+ foreach (var w6 in (w5 as Gtk.Container).get_children ()) {
300+ if (w6.get_name () == GTK_CREATEFOLDER_BUTTON_PATH[2])
301+ /* Register the button so we can use it's signal */
302+ gtk_folder_button = w6.@ref () as Gtk.Button;
303+ }
304+ }
305+ }
306+ }
307+ }
308+
309+ (w2 as Gtk.Container).remove (w3);
310+ }
311+ }
312+ }
313+
314+ private static void assign_container_box () {
315+ var tmp = d.get_widget_for_response (BUTTON_RESPONSE);
316+
317+ var container = tmp.get_parent ();
318+ container_box = container.get_parent () as Gtk.Box;
319+ }
320+
321+ private static void setup_filter_box () {
322+ var filters = chooser.list_filters ();
323+ if (filters.length () > 0) {
324+ filters_available = true;
325+ var combo_box = new Gtk.ComboBoxText ();
326+
327+ if (chooser.get_action () == Gtk.FileChooserAction.SAVE)
328+ combo_box.margin_top = 8;
329+ else
330+ combo_box.margin_top = 4;
331+
332+ combo_box.changed.connect (() => {
333+ chooser.list_filters ().@foreach ((filter) => {
334+ if (filter.get_filter_name () == combo_box.get_active_text ())
335+ chooser.set_filter (filter);
336+ });
337+ });
338+
339+ filters.foreach ((filter) => {
340+ combo_box.append_text (filter.get_filter_name ());
341+ });
342+
343+ combo_box.active = 0;
344+
345+ var grid = new Gtk.Grid ();
346+ grid.margin_start = 5;
347+ grid.add (combo_box);
348+ container_box.add (grid);
349+ }
350+ }
351+}
352\ No newline at end of file
353
354=== added file 'filechooser-module/LocationBarChooser.vala'
355--- filechooser-module/LocationBarChooser.vala 1970-01-01 00:00:00 +0000
356+++ filechooser-module/LocationBarChooser.vala 2015-05-30 21:14:32 +0000
357@@ -0,0 +1,280 @@
358+// -*- Mode: vala; indent-tabs-mode: nil; tab-width: 4 -*-
359+/*-
360+ * Copyright (c) 2015 Pantheon Developers (http://launchpad.net/elementary)
361+ *
362+ * This library is free software; you can redistribute it and/or
363+ * modify it under the terms of the GNU Library General Public
364+ * License as published by the Free Software Foundation; either
365+ * version 2 of the License, or (at your option) any later version.
366+ *
367+ * This library is distributed in the hope that it will be useful,
368+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
369+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
370+ * Library General Public License for more details.
371+ *
372+ * You should have received a copy of the GNU Library General Public
373+ * License along with this library; if not, write to the
374+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
375+ * Boston, MA 02111-1307, USA.
376+ *
377+ * Authored by: Corentin Noël <tintou@mailoo.org>
378+ */
379+
380+namespace Marlin {
381+ private const string ICON_FILESYSTEM_SYMBOLIC = "drive-harddisk-symbolic";
382+ private const string ICON_FOLDER_DOCUMENTS_SYMBOLIC = "folder-documents-symbolic";
383+ private const string ICON_FOLDER_DOWNLOADS_SYMBOLIC = "folder-download-symbolic";
384+ private const string ICON_FOLDER_MUSIC_SYMBOLIC = "folder-music-symbolic";
385+ private const string ICON_FOLDER_PICTURES_SYMBOLIC = "folder-pictures-symbolic";
386+ private const string ICON_FOLDER_REMOTE = "folder-remote";
387+ private const string ICON_FOLDER_REMOTE_SYMBOLIC = "folder-remote-symbolic";
388+ private const string ICON_FOLDER_TEMPLATES_SYMBOLIC = "folder-templates-symbolic";
389+ private const string ICON_FOLDER_VIDEOS_SYMBOLIC = "folder-videos-symbolic";
390+ private const string ICON_GO_HOME_SYMBOLIC = "go-home-symbolic";
391+ private const string ICON_NETWORK = "network-workgroup";
392+ private const string ICON_NETWORK_SERVER = "network-server";
393+ private const string ICON_TRASH = "user-trash";
394+ private const string ICON_TRASH_FULL = "user-trash-full";
395+ private const string ICON_TRASH_SYMBOLIC = "user-trash-symbolic";
396+
397+ private const string PROTOCOL_NAME_AFP = "AFP";
398+ private const string PROTOCOL_NAME_DAV = "DAV";
399+ private const string PROTOCOL_NAME_DAVS = "DAVS";
400+ private const string PROTOCOL_NAME_FTP = "FTP";
401+ private const string PROTOCOL_NAME_NETWORK = "Network";
402+ private const string PROTOCOL_NAME_SFTP = "SFTP";
403+ private const string PROTOCOL_NAME_SMB = "SMB";
404+ private const string PROTOCOL_NAME_TRASH = "Trash";
405+}
406+
407+namespace Marlin.View.Chrome {
408+ public class LocationBar : Gtk.Box {
409+ public Breadcrumbs bread;
410+
411+ private string _path;
412+ public new string path {
413+ set {
414+ var new_path = GLib.Uri.unescape_string (value);
415+ if (new_path != null) {
416+ _path = new_path;
417+
418+ if (!bread.is_focus) {
419+ bread.text = "";
420+ bread.change_breadcrumbs (new_path);
421+ }
422+ } else
423+ warning ("Tried to set null path\n");
424+ }
425+
426+ get {
427+ return _path;
428+ }
429+ }
430+
431+ public new signal void activate (GLib.File file);
432+ public signal void escape ();
433+ public signal void change_to_file (string filename);
434+
435+ public override void get_preferred_width (out int minimum_width, out int natural_width) {
436+ minimum_width = -1;
437+ natural_width = 3000;
438+ }
439+
440+ public LocationBar (Gtk.Widget parent) {
441+ bread = new Breadcrumbs ();
442+ bread.escape.connect (() => { escape (); });
443+ bread.activate_alternate.connect ((file) => {
444+ path = "file://" + file.get_path ();
445+ change_to_file (file.get_path ());
446+ });
447+
448+ bread.path_changed.connect ((file) => {
449+ path = "file://" + file.get_path ();
450+ change_to_file (file.get_path ());
451+
452+ parent.grab_focus ();
453+ });
454+
455+ margin_top = 4;
456+ margin_bottom = 4;
457+ margin_left = 3;
458+ pack_start (bread, true, true, 0);
459+ }
460+ }
461+
462+ public class Breadcrumbs : BasePathBar {
463+ Gtk.Menu menu;
464+
465+ private bool drop_data_ready = false;
466+ private bool drop_occurred = false;
467+ private GLib.List<GLib.File> drop_file_list = null;
468+
469+ Gdk.DragAction current_suggested_action = 0;
470+ Gdk.DragAction current_actions = 0;
471+
472+ public Breadcrumbs ()
473+ {
474+ /* The string split of the path url is kinda too basic,
475+ * we should use the GFile to split our uris and determine the protocol (if any) with g_uri_parse_scheme or g_file_get_uri_scheme */
476+ add_icon ({ "afp://", Marlin.ICON_FOLDER_REMOTE_SYMBOLIC, true, null, null, null, true, Marlin.PROTOCOL_NAME_AFP});
477+ add_icon ({ "dav://", Marlin.ICON_FOLDER_REMOTE_SYMBOLIC, true, null, null, null, true, Marlin.PROTOCOL_NAME_DAV});
478+ add_icon ({ "davs://", Marlin.ICON_FOLDER_REMOTE_SYMBOLIC, true, null, null, null, true,Marlin.PROTOCOL_NAME_DAVS});
479+ add_icon ({ "ftp://", Marlin.ICON_FOLDER_REMOTE_SYMBOLIC, true, null, null, null, true, Marlin.PROTOCOL_NAME_FTP});
480+ add_icon ({ "network://", Marlin.ICON_FOLDER_REMOTE_SYMBOLIC, true, null, null, null, true, Marlin.PROTOCOL_NAME_NETWORK});
481+ add_icon ({ "sftp://", Marlin.ICON_FOLDER_REMOTE_SYMBOLIC, true, null, null, null, true, Marlin.PROTOCOL_NAME_SFTP});
482+ add_icon ({ "smb://", Marlin.ICON_FOLDER_REMOTE_SYMBOLIC, true, null, null, null, true,Marlin.PROTOCOL_NAME_SMB});
483+ add_icon ({ "trash://", Marlin.ICON_TRASH_SYMBOLIC, true, null, null, null, true, Marlin.PROTOCOL_NAME_TRASH});
484+
485+ string dir;
486+ dir = Environment.get_user_special_dir (UserDirectory.MUSIC);
487+ if (dir.contains ("/")) {
488+ IconDirectory icon = {dir, Marlin.ICON_FOLDER_MUSIC_SYMBOLIC, false, null, null, dir.split ("/"), false, null};
489+ icon.exploded[0] = "/";
490+ add_icon (icon);
491+ }
492+
493+
494+ dir = Environment.get_user_special_dir (UserDirectory.PICTURES);
495+ if (dir.contains ("/")) {
496+ IconDirectory icon = {dir, Marlin.ICON_FOLDER_PICTURES_SYMBOLIC, false, null, null, dir.split ("/"), false, null};
497+ icon.exploded[0] = "/";
498+ add_icon (icon);
499+ }
500+
501+
502+ dir = Environment.get_user_special_dir (UserDirectory.VIDEOS);
503+ if (dir.contains ("/")) {
504+ IconDirectory icon = {dir, Marlin.ICON_FOLDER_VIDEOS_SYMBOLIC, false, null, null, dir.split ("/"), false, null};
505+ icon.exploded[0] = "/";
506+ add_icon (icon);
507+ }
508+
509+ dir = Environment.get_user_special_dir (UserDirectory.DOWNLOAD);
510+ if (dir.contains ("/")) {
511+ IconDirectory icon = {dir, Marlin.ICON_FOLDER_DOWNLOADS_SYMBOLIC, false, null, null, dir.split ("/"), false, null};
512+ icon.exploded[0] = "/";
513+ add_icon (icon);
514+ }
515+
516+ dir = Environment.get_user_special_dir (UserDirectory.DOCUMENTS);
517+ if (dir.contains ("/")) {
518+ IconDirectory icon = {dir, Marlin.ICON_FOLDER_DOCUMENTS_SYMBOLIC, false, null, null, dir.split ("/"), false, null};
519+ icon.exploded[0] = "/";
520+ add_icon (icon);
521+ }
522+
523+ dir = Environment.get_user_special_dir (UserDirectory.TEMPLATES);
524+ if (dir.contains ("/")) {
525+ IconDirectory icon = {dir, Marlin.ICON_FOLDER_TEMPLATES_SYMBOLIC, false, null, null, dir.split ("/"), false, null};
526+ icon.exploded[0] = "/";
527+ add_icon (icon);
528+ }
529+
530+ dir = Environment.get_home_dir ();
531+ if (dir.contains ("/")) {
532+ IconDirectory icon = {dir, Marlin.ICON_GO_HOME_SYMBOLIC, false, null, null, dir.split ("/"), true, null};
533+ icon.exploded[0] = "/";
534+ add_icon (icon);
535+ }
536+
537+
538+ dir = "/media";
539+ if (dir.contains ("/")) {
540+ IconDirectory icon = {dir, Marlin.ICON_FILESYSTEM_SYMBOLIC, false, null, null, dir.split ("/"), true, null};
541+ icon.exploded[0] = "/";
542+ add_icon (icon);
543+ }
544+
545+ IconDirectory icon = {"/", Marlin.ICON_FILESYSTEM_SYMBOLIC, false, null, null, null, false, null};
546+ icon.exploded = {"/"};
547+ add_icon (icon);
548+
549+ menu = new Gtk.Menu ();
550+ menu.show_all ();
551+ }
552+
553+ protected override void load_right_click_menu (double x, double y) {
554+
555+ }
556+
557+ protected override bool on_drag_motion (Gdk.DragContext context, int x, int y, uint time) {
558+ Gtk.drag_unhighlight (this);
559+
560+ foreach (BreadcrumbsElement element in elements)
561+ element.pressed = false;
562+
563+ var el = get_element_from_coordinates (x, y);
564+
565+ if (el != null)
566+ el.pressed = true;
567+ else
568+ /* No action taken on drop */
569+ Gdk.drag_status (context, 0, time);
570+
571+ queue_draw ();
572+
573+ return false;
574+ }
575+
576+ protected override bool on_drag_drop (Gdk.DragContext context,
577+ int x,
578+ int y,
579+ uint timestamp) {
580+ Gtk.TargetList list = null;
581+ bool ok_to_drop = false;
582+
583+ Gdk.Atom target = Gtk.drag_dest_find_target (this, context, list);
584+
585+ ok_to_drop = (target != Gdk.Atom.NONE);
586+
587+ if (ok_to_drop) {
588+ drop_occurred = true;
589+ Gtk.drag_get_data (this, context, target, timestamp);
590+ }
591+
592+ return ok_to_drop;
593+ }
594+
595+ protected override void on_drag_data_received (Gdk.DragContext context,
596+ int x,
597+ int y,
598+ Gtk.SelectionData selection_data,
599+ uint info,
600+ uint timestamp) {
601+ bool success = false;
602+
603+ if (!drop_data_ready) {
604+ drop_file_list = null;
605+ foreach (var uri in selection_data.get_uris ()) {
606+ debug ("Path to move: %s\n", uri);
607+ drop_file_list.append (File.new_for_uri (uri));
608+ drop_data_ready = true;
609+ }
610+ }
611+
612+ if (drop_data_ready && drop_occurred && info == TargetType.TEXT_URI_LIST) {
613+ drop_occurred = false;
614+ current_actions = 0;
615+ current_suggested_action = 0;
616+
617+ Gtk.drag_finish (context, success, false, timestamp);
618+ on_drag_leave (context, timestamp);
619+ }
620+ }
621+
622+ protected override void on_drag_leave (Gdk.DragContext drag_context, uint time) {
623+ foreach (BreadcrumbsElement element in elements) {
624+ if (element.pressed) {
625+ element.pressed = false;
626+ break;
627+ }
628+ }
629+
630+ drop_occurred = false;
631+ drop_data_ready = false;
632+ drop_file_list = null;
633+
634+ queue_draw ();
635+ }
636+ }
637+}
638
639=== added file 'filechooser-module/Plugin.vala'
640--- filechooser-module/Plugin.vala 1970-01-01 00:00:00 +0000
641+++ filechooser-module/Plugin.vala 2015-05-30 21:14:32 +0000
642@@ -0,0 +1,57 @@
643+// -*- Mode: vala; indent-tabs-mode: nil; tab-width: 4 -*-
644+/*-
645+ * Copyright (c) 2013 Pantheon Developers (http://launchpad.net/elementary)
646+ *
647+ * This library is free software; you can redistribute it and/or
648+ * modify it under the terms of the GNU Library General Public
649+ * License as published by the Free Software Foundation; either
650+ * version 2 of the License, or (at your option) any later version.
651+ *
652+ * This library is distributed in the hope that it will be useful,
653+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
654+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
655+ * Library General Public License for more details.
656+ *
657+ * You should have received a copy of the GNU Library General Public
658+ * License along with this library; if not, write to the
659+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
660+ * Boston, MA 02111-1307, USA.
661+ *
662+ * Authored by: Corentin Noël <tintou@mailoo.org>
663+ */
664+
665+public class PantheonModule.FileChooserDialog : GLib.Object {
666+ /* Catching dialogs section by: tintou (https://launchpad.net/~tintou) */
667+ Gee.TreeSet<Gtk.FileChooserDialog> tree_set;
668+ public FileChooserDialog () {
669+ tree_set = new Gee.TreeSet<Gtk.FileChooserDialog> ();
670+ /* It's the only way to get every new window */
671+ var map_id = GLib.Signal.lookup ("window-state-event", typeof (Gtk.Dialog));
672+ GLib.Signal.add_emission_hook (map_id, 0, (ihint, param_values) => {
673+ if (param_values[0].type () == typeof (Gtk.FileChooserDialog)) {
674+ var dialog = (Gtk.FileChooserDialog)param_values [0];//.dup_object ();
675+ if (tree_set.contains (dialog) == false) {
676+ tree_set.add (dialog);
677+
678+ var dialog_new = new CustomFileChooserDialog (dialog);
679+ dialog_new.set_open_path (dialog.get_current_folder ());
680+ dialog.destroy.connect (() => {
681+ tree_set.remove (dialog);
682+ });
683+ }
684+ }
685+
686+ return true;
687+ }, null);
688+ }
689+}
690+
691+public static PantheonModule.FileChooserDialog filechooser_module = null;
692+public void gtk_module_init ([CCode (array_length_cname = "argc", array_length_pos = 0.5)] ref unowned string[]? argv) {
693+ if (Gtk.check_version (3, 14, 0) == null) {
694+ var appinfo = AppInfo.get_default_for_type ("inode/directory", true);
695+ if (appinfo.get_executable () == "pantheon-files")
696+ filechooser_module = new PantheonModule.FileChooserDialog ();
697+ } else
698+ warning ("The required GTK version is 3.14");
699+}
700\ No newline at end of file

Subscribers

People subscribed via source and target branches

to all changes: