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

Proposed by Adam Bieńkowski
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
Fabio Zaramella (community) Needs Information
Daniel Fore ux Approve
elementary Apps team code 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.
Revision history for this message
Rico Tzschichholz (ricotz) wrote :

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

Revision history for this message
Rico Tzschichholz (ricotz) wrote :

Don't touch po/* that way

Revision history for this message
Rico Tzschichholz (ricotz) wrote :
Revision history for this message
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
Revision history for this message
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.

Revision history for this message
Daniel Fore (danrabbit) wrote :

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

Revision history for this message
Aneurin Hall (aneurin-hall) wrote :

will this finally bring in icon view and scaling?

Revision history for this message
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)
Revision history for this message
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
Revision history for this message
Adam Bieńkowski (donadigo) wrote :

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

Revision history for this message
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
Revision history for this message
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.

Revision history for this message
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.

Revision history for this message
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

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

Revision history for this message
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

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

Revision history for this message
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
=== modified file 'CMakeLists.txt'
--- CMakeLists.txt 2015-05-16 11:43:17 +0000
+++ CMakeLists.txt 2015-05-30 21:14:32 +0000
@@ -19,13 +19,16 @@
19add_definitions ("-w")19add_definitions ("-w")
2020
21option (LIB_ONLY "Build libcore and libwidgets only" FALSE)21option (LIB_ONLY "Build libcore and libwidgets only" FALSE)
22option (MODULE_ONLY "Build only custom gtk filechooser dialog module" FALSE)
2223
23find_package (Vala REQUIRED)24find_package (Vala REQUIRED)
24include (ValaVersion)25include (ValaVersion)
25ensure_vala_version ("0.26" MINIMUM)26ensure_vala_version ("0.26" MINIMUM)
26include (ValaPrecompile)27include (ValaPrecompile)
2728
28IF (LIB_ONLY)29if (MODULE_ONLY)
30 add_subdirectory (filechooser-module)
31ELSEIF (LIB_ONLY)
29 add_subdirectory (libcore)32 add_subdirectory (libcore)
30 add_subdirectory (libwidgets)33 add_subdirectory (libwidgets)
31ELSE ()34ELSE ()
@@ -35,5 +38,6 @@
35 add_subdirectory (libcore)38 add_subdirectory (libcore)
36 add_subdirectory (libwidgets)39 add_subdirectory (libwidgets)
37 add_subdirectory (plugins)40 add_subdirectory (plugins)
41 add_subdirectory (filechooser-module)
38 add_subdirectory (po)42 add_subdirectory (po)
39ENDIF (LIB_ONLY)43ENDIF ()
4044
=== modified file 'INSTALL'
--- INSTALL 2014-07-28 01:14:13 +0000
+++ INSTALL 2015-05-30 21:14:32 +0000
@@ -39,3 +39,6 @@
3939
40 To install only libcore and libwidgets use the following command:40 To install only libcore and libwidgets use the following command:
41 cmake .. -DLIB_ONLY=true41 cmake .. -DLIB_ONLY=true
42
43 To install only the Gtk-Module use the following command:
44 cmake .. -DMODULE_ONLY=true
4245
=== added directory 'filechooser-module'
=== added file 'filechooser-module/CMakeLists.txt'
--- filechooser-module/CMakeLists.txt 1970-01-01 00:00:00 +0000
+++ filechooser-module/CMakeLists.txt 2015-05-30 21:14:32 +0000
@@ -0,0 +1,29 @@
1find_package (PkgConfig)
2
3pkg_check_modules (DEPS REQUIRED glib-2.0 gthread-2.0 gtk+-3.0>=3.10 granite gee-0.8)
4add_definitions (${DEPS_CFLAGS})
5link_directories (${DEPS_LIBRARY_DIRS})
6set (MODULE_NAME "pantheon-filechooser-module")
7set (MOULDE_LIBDIR "/usr/lib/x86_64-linux-gnu")
8
9vala_precompile (VALA_C ${MODULE_NAME}
10 ${CMAKE_SOURCE_DIR}/libwidgets/LocationBar.vala
11 ${CMAKE_SOURCE_DIR}/libwidgets/BreadcrumbsElements.vala
12 LocationBarChooser.vala
13 FileChooserDialog.vala
14 Plugin.vala
15PACKAGES
16 gtk+-3.0
17 granite
18 posix
19 gee-0.8
20OPTIONS
21 --thread
22)
23
24link_libraries(${DEPS_LIBRARIES})
25add_library (${MODULE_NAME} MODULE ${VALA_C})
26target_link_libraries (${MODULE_NAME} ${DEPS_LIBRARIES} gthread-2.0)
27
28# Installation
29install (TARGETS ${MODULE_NAME} DESTINATION "${MOULDE_LIBDIR}/gtk-3.0/modules/")
030
=== added file 'filechooser-module/FileChooserDialog.vala'
--- filechooser-module/FileChooserDialog.vala 1970-01-01 00:00:00 +0000
+++ filechooser-module/FileChooserDialog.vala 2015-05-30 21:14:32 +0000
@@ -0,0 +1,271 @@
1/*-
2 * Copyright (c) 2015 Pantheon Developers (http://launchpad.net/elementary)
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Library General Public License for more details.
13 *
14 * You should have received a copy of the GNU Library General Public
15 * License along with this library; if not, write to the
16 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17 * Boston, MA 02111-1307, USA.
18 *
19 * Authored by: Adam Bieńkowski <donadigos159@gmail.com>
20 */
21
22public class CustomFileChooserDialog : Object {
23 private static Gtk.FileChooser chooser;
24
25 private static Gtk.FileChooserDialog d;
26 private static Gtk.Widget rootwidget;
27
28 private static Gtk.Box container_box;
29 private static Gtk.Button? gtk_folder_button = null;
30
31 /* Response to get parent of the bottom box */
32 private const int BUTTON_RESPONSE = -6;
33
34 /* Paths to widgets */
35 private const string[] GTK_PATHBAR_PATH = { "widget", "browse_widgets_box", "browse_files_box", "browse_header_box" };
36 private const string[] GTK_FILTERCHOOSER_PATH = { "extra_and_filters", "filter_combo_hbox" };
37 private const string[] GTK_CREATEFOLDER_BUTTON_PATH = { "browse_header_stack", "browse_path_bar_hbox", "browse_new_folder_button" };
38 private const string PLACES_SIDEBAR_PATH = "places_sidebar";
39
40 private const string FILE_PREFIX = "file://";
41
42 private GenericArray<string> forward_path_list = new GenericArray<string> ();
43 private Gee.ArrayList<string> history = new Gee.ArrayList<string> ();
44
45 private static bool filters_available = false;
46
47 private static string open_path;
48 private string previous_path = "";
49
50 public CustomFileChooserDialog (Gtk.FileChooserDialog _dialog) {
51 /* The "d" variable is the main dialog */
52 d = _dialog;
53 d.can_focus = true;
54
55 /* Main FileChooser interface */
56 chooser = (d as Gtk.FileChooser);
57
58 d.deletable = false;
59 assign_container_box ();
60 setup_filter_box ();
61 remove_gtk_widgets ();
62
63 var header_bar = new Gtk.HeaderBar ();
64
65 var button_back = new Gtk.Button.from_icon_name ("go-previous-symbolic", Gtk.IconSize.LARGE_TOOLBAR);
66 button_back.tooltip_text = _("Previous");
67 button_back.sensitive = false;
68
69 var button_forward = new Gtk.Button.from_icon_name ("go-next-symbolic", Gtk.IconSize.LARGE_TOOLBAR);
70 button_forward.tooltip_text = _("Next");
71 button_forward.sensitive = false;
72
73 var pathbar = new Marlin.View.Chrome.LocationBar (rootwidget);
74 pathbar.path = FILE_PREFIX + chooser.get_current_folder ();
75 pathbar.hexpand = true;
76
77 header_bar.pack_start (button_back);
78 header_bar.pack_start (button_forward);
79 header_bar.pack_start (pathbar);
80 if ((gtk_folder_button != null) && (chooser.get_action () != Gtk.FileChooserAction.OPEN)) {
81 var create_folder_button = new Gtk.Button.from_icon_name ("folder-new", Gtk.IconSize.LARGE_TOOLBAR);
82 create_folder_button.set_tooltip_text (_("Create folder"));
83 create_folder_button.clicked.connect (() => {
84 gtk_folder_button.clicked ();
85 });
86
87 header_bar.pack_end (create_folder_button);
88 }
89
90 d.set_titlebar (header_bar);
91 d.show_all ();
92
93 button_back.clicked.connect (() => {
94 forward_path_list.add (chooser.get_current_folder ());
95
96 history.remove (history.last ());
97 chooser.set_current_folder (history.last ());
98 history.remove (history.last ());
99 });
100
101 button_forward.clicked.connect (() => {
102 if (forward_path_list.length > 0) {
103 int length = forward_path_list.length - 1;
104
105 pathbar.path = FILE_PREFIX + forward_path_list.@get (length);
106 chooser.set_current_folder (forward_path_list.@get (length));
107 forward_path_list.remove (forward_path_list.@get (length));
108 }
109 });
110
111 chooser.current_folder_changed.connect (() => {
112 if (history.size > 0)
113 previous_path = history.last ();
114 else if (open_path != chooser.get_current_folder ()) {
115 previous_path = "";
116 history.add (open_path);
117 }
118
119 button_back.sensitive = (history.size > 0);
120 button_forward.sensitive = (forward_path_list.length > 0);
121
122 if (chooser.get_current_folder () != previous_path)
123 history.add (chooser.get_current_folder ());
124
125 pathbar.path = FILE_PREFIX + chooser.get_current_folder ();
126 });
127
128 pathbar.change_to_file.connect ((file) => {
129 chooser.set_current_folder (file);
130 });
131 }
132
133 public void set_open_path (string _open_path) {
134 open_path = _open_path;
135 previous_path = open_path;
136 chooser.set_current_folder (open_path);
137 }
138
139 /* Remove GTK's native path bar and FileFilter chooser by widgets names */
140 private static void remove_gtk_widgets () {
141 foreach (var root in d.get_children ()) {
142 foreach (var w0 in (root as Gtk.Container).get_children ()) {
143 if (w0.get_name () == GTK_PATHBAR_PATH[0]) {
144 /* Add top separator between headerbar and filechooser when is not Save action */
145 var chooserwidget = w0 as Gtk.Container;
146 chooserwidget.vexpand = true;
147
148 (root as Gtk.Container).remove (w0);
149 var root_box = new Gtk.Box (Gtk.Orientation.VERTICAL, 0);
150 root_box.add (new Gtk.Separator (Gtk.Orientation.HORIZONTAL));
151 root_box.add (chooserwidget);
152
153 if (chooser.get_extra_widget () == null)
154 root_box.add (new Gtk.Separator (Gtk.Orientation.HORIZONTAL));
155
156 (root as Gtk.Container).add (root_box);
157 rootwidget = chooserwidget;
158 rootwidget = w0;
159 rootwidget.can_focus = true;
160 transform_rootwidget_container (rootwidget, w0);
161 }
162 }
163 }
164 }
165
166 private static void transform_rootwidget_container (Gtk.Widget rootwidget, Gtk.Widget w0) {
167 foreach (var w1 in (rootwidget as Gtk.Container).get_children ()) {
168 if (w1.name == "GtkBox" && w1.get_name () != GTK_PATHBAR_PATH[1]) {
169 var new_w1 = w1.@ref ();
170 (rootwidget as Gtk.Container).remove (w1);
171
172 foreach (var grid in (new_w1 as Gtk.Container).get_children ()) {
173 if (grid != null) {
174 var new_grid = grid.@ref ();
175 (new_grid as Gtk.Widget).margin = 0;
176 (new_w1 as Gtk.Container).remove (grid);
177 container_box.add (new_grid as Gtk.Widget);
178 }
179 }
180
181 container_box.show_all ();
182 } else if (w1.get_name () == GTK_PATHBAR_PATH[1])
183 transform_w1_container (w1);
184 else {
185 if (w1.get_name () == GTK_FILTERCHOOSER_PATH[0]) {
186 /* Remove extra_and_filters if there is no extra widget */
187 if (chooser.get_extra_widget () == null)
188 (w0 as Gtk.Container).remove (w1);
189 else {
190 foreach (var w5 in (w1 as Gtk.Container).get_children ()) {
191 if (w5.get_name () == GTK_FILTERCHOOSER_PATH[1])
192 (w1 as Gtk.Container).remove (w5);
193 }
194 }
195 }
196 }
197 }
198 }
199
200 private static void transform_w1_container (Gtk.Widget w1) {
201 foreach (var paned in (w1 as Gtk.Container).get_children ()) {
202 foreach (var w2 in (paned as Gtk.Container).get_children ()) {
203 if (w2.get_name () == PLACES_SIDEBAR_PATH) {
204 (w2 as Gtk.PlacesSidebar).show_desktop = false;
205 (w2 as Gtk.PlacesSidebar).show_enter_location = false;
206 } else if (w2.get_name () == GTK_PATHBAR_PATH[2])
207 transform_w2_container (w2);
208 }
209 }
210 }
211
212 private static void transform_w2_container (Gtk.Widget w2) {
213 foreach (var w3 in (w2 as Gtk.Container).get_children ()) {
214 if (w3.get_name () == GTK_PATHBAR_PATH[3]) {
215 foreach (var w4 in (w3 as Gtk.Container).get_children ()) {
216 if (w4.get_name () == GTK_CREATEFOLDER_BUTTON_PATH[0]) {
217 foreach (var w5 in (w4 as Gtk.Container).get_children ()) {
218 if (w5.get_name () == GTK_CREATEFOLDER_BUTTON_PATH[1]) {
219 foreach (var w6 in (w5 as Gtk.Container).get_children ()) {
220 if (w6.get_name () == GTK_CREATEFOLDER_BUTTON_PATH[2])
221 /* Register the button so we can use it's signal */
222 gtk_folder_button = w6.@ref () as Gtk.Button;
223 }
224 }
225 }
226 }
227 }
228
229 (w2 as Gtk.Container).remove (w3);
230 }
231 }
232 }
233
234 private static void assign_container_box () {
235 var tmp = d.get_widget_for_response (BUTTON_RESPONSE);
236
237 var container = tmp.get_parent ();
238 container_box = container.get_parent () as Gtk.Box;
239 }
240
241 private static void setup_filter_box () {
242 var filters = chooser.list_filters ();
243 if (filters.length () > 0) {
244 filters_available = true;
245 var combo_box = new Gtk.ComboBoxText ();
246
247 if (chooser.get_action () == Gtk.FileChooserAction.SAVE)
248 combo_box.margin_top = 8;
249 else
250 combo_box.margin_top = 4;
251
252 combo_box.changed.connect (() => {
253 chooser.list_filters ().@foreach ((filter) => {
254 if (filter.get_filter_name () == combo_box.get_active_text ())
255 chooser.set_filter (filter);
256 });
257 });
258
259 filters.foreach ((filter) => {
260 combo_box.append_text (filter.get_filter_name ());
261 });
262
263 combo_box.active = 0;
264
265 var grid = new Gtk.Grid ();
266 grid.margin_start = 5;
267 grid.add (combo_box);
268 container_box.add (grid);
269 }
270 }
271}
0\ No newline at end of file272\ No newline at end of file
1273
=== added file 'filechooser-module/LocationBarChooser.vala'
--- filechooser-module/LocationBarChooser.vala 1970-01-01 00:00:00 +0000
+++ filechooser-module/LocationBarChooser.vala 2015-05-30 21:14:32 +0000
@@ -0,0 +1,280 @@
1// -*- Mode: vala; indent-tabs-mode: nil; tab-width: 4 -*-
2/*-
3 * Copyright (c) 2015 Pantheon Developers (http://launchpad.net/elementary)
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Library General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Library General Public License for more details.
14 *
15 * You should have received a copy of the GNU Library General Public
16 * License along with this library; if not, write to the
17 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 * Boston, MA 02111-1307, USA.
19 *
20 * Authored by: Corentin Noël <tintou@mailoo.org>
21 */
22
23namespace Marlin {
24 private const string ICON_FILESYSTEM_SYMBOLIC = "drive-harddisk-symbolic";
25 private const string ICON_FOLDER_DOCUMENTS_SYMBOLIC = "folder-documents-symbolic";
26 private const string ICON_FOLDER_DOWNLOADS_SYMBOLIC = "folder-download-symbolic";
27 private const string ICON_FOLDER_MUSIC_SYMBOLIC = "folder-music-symbolic";
28 private const string ICON_FOLDER_PICTURES_SYMBOLIC = "folder-pictures-symbolic";
29 private const string ICON_FOLDER_REMOTE = "folder-remote";
30 private const string ICON_FOLDER_REMOTE_SYMBOLIC = "folder-remote-symbolic";
31 private const string ICON_FOLDER_TEMPLATES_SYMBOLIC = "folder-templates-symbolic";
32 private const string ICON_FOLDER_VIDEOS_SYMBOLIC = "folder-videos-symbolic";
33 private const string ICON_GO_HOME_SYMBOLIC = "go-home-symbolic";
34 private const string ICON_NETWORK = "network-workgroup";
35 private const string ICON_NETWORK_SERVER = "network-server";
36 private const string ICON_TRASH = "user-trash";
37 private const string ICON_TRASH_FULL = "user-trash-full";
38 private const string ICON_TRASH_SYMBOLIC = "user-trash-symbolic";
39
40 private const string PROTOCOL_NAME_AFP = "AFP";
41 private const string PROTOCOL_NAME_DAV = "DAV";
42 private const string PROTOCOL_NAME_DAVS = "DAVS";
43 private const string PROTOCOL_NAME_FTP = "FTP";
44 private const string PROTOCOL_NAME_NETWORK = "Network";
45 private const string PROTOCOL_NAME_SFTP = "SFTP";
46 private const string PROTOCOL_NAME_SMB = "SMB";
47 private const string PROTOCOL_NAME_TRASH = "Trash";
48}
49
50namespace Marlin.View.Chrome {
51 public class LocationBar : Gtk.Box {
52 public Breadcrumbs bread;
53
54 private string _path;
55 public new string path {
56 set {
57 var new_path = GLib.Uri.unescape_string (value);
58 if (new_path != null) {
59 _path = new_path;
60
61 if (!bread.is_focus) {
62 bread.text = "";
63 bread.change_breadcrumbs (new_path);
64 }
65 } else
66 warning ("Tried to set null path\n");
67 }
68
69 get {
70 return _path;
71 }
72 }
73
74 public new signal void activate (GLib.File file);
75 public signal void escape ();
76 public signal void change_to_file (string filename);
77
78 public override void get_preferred_width (out int minimum_width, out int natural_width) {
79 minimum_width = -1;
80 natural_width = 3000;
81 }
82
83 public LocationBar (Gtk.Widget parent) {
84 bread = new Breadcrumbs ();
85 bread.escape.connect (() => { escape (); });
86 bread.activate_alternate.connect ((file) => {
87 path = "file://" + file.get_path ();
88 change_to_file (file.get_path ());
89 });
90
91 bread.path_changed.connect ((file) => {
92 path = "file://" + file.get_path ();
93 change_to_file (file.get_path ());
94
95 parent.grab_focus ();
96 });
97
98 margin_top = 4;
99 margin_bottom = 4;
100 margin_left = 3;
101 pack_start (bread, true, true, 0);
102 }
103 }
104
105 public class Breadcrumbs : BasePathBar {
106 Gtk.Menu menu;
107
108 private bool drop_data_ready = false;
109 private bool drop_occurred = false;
110 private GLib.List<GLib.File> drop_file_list = null;
111
112 Gdk.DragAction current_suggested_action = 0;
113 Gdk.DragAction current_actions = 0;
114
115 public Breadcrumbs ()
116 {
117 /* The string split of the path url is kinda too basic,
118 * 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 */
119 add_icon ({ "afp://", Marlin.ICON_FOLDER_REMOTE_SYMBOLIC, true, null, null, null, true, Marlin.PROTOCOL_NAME_AFP});
120 add_icon ({ "dav://", Marlin.ICON_FOLDER_REMOTE_SYMBOLIC, true, null, null, null, true, Marlin.PROTOCOL_NAME_DAV});
121 add_icon ({ "davs://", Marlin.ICON_FOLDER_REMOTE_SYMBOLIC, true, null, null, null, true,Marlin.PROTOCOL_NAME_DAVS});
122 add_icon ({ "ftp://", Marlin.ICON_FOLDER_REMOTE_SYMBOLIC, true, null, null, null, true, Marlin.PROTOCOL_NAME_FTP});
123 add_icon ({ "network://", Marlin.ICON_FOLDER_REMOTE_SYMBOLIC, true, null, null, null, true, Marlin.PROTOCOL_NAME_NETWORK});
124 add_icon ({ "sftp://", Marlin.ICON_FOLDER_REMOTE_SYMBOLIC, true, null, null, null, true, Marlin.PROTOCOL_NAME_SFTP});
125 add_icon ({ "smb://", Marlin.ICON_FOLDER_REMOTE_SYMBOLIC, true, null, null, null, true,Marlin.PROTOCOL_NAME_SMB});
126 add_icon ({ "trash://", Marlin.ICON_TRASH_SYMBOLIC, true, null, null, null, true, Marlin.PROTOCOL_NAME_TRASH});
127
128 string dir;
129 dir = Environment.get_user_special_dir (UserDirectory.MUSIC);
130 if (dir.contains ("/")) {
131 IconDirectory icon = {dir, Marlin.ICON_FOLDER_MUSIC_SYMBOLIC, false, null, null, dir.split ("/"), false, null};
132 icon.exploded[0] = "/";
133 add_icon (icon);
134 }
135
136
137 dir = Environment.get_user_special_dir (UserDirectory.PICTURES);
138 if (dir.contains ("/")) {
139 IconDirectory icon = {dir, Marlin.ICON_FOLDER_PICTURES_SYMBOLIC, false, null, null, dir.split ("/"), false, null};
140 icon.exploded[0] = "/";
141 add_icon (icon);
142 }
143
144
145 dir = Environment.get_user_special_dir (UserDirectory.VIDEOS);
146 if (dir.contains ("/")) {
147 IconDirectory icon = {dir, Marlin.ICON_FOLDER_VIDEOS_SYMBOLIC, false, null, null, dir.split ("/"), false, null};
148 icon.exploded[0] = "/";
149 add_icon (icon);
150 }
151
152 dir = Environment.get_user_special_dir (UserDirectory.DOWNLOAD);
153 if (dir.contains ("/")) {
154 IconDirectory icon = {dir, Marlin.ICON_FOLDER_DOWNLOADS_SYMBOLIC, false, null, null, dir.split ("/"), false, null};
155 icon.exploded[0] = "/";
156 add_icon (icon);
157 }
158
159 dir = Environment.get_user_special_dir (UserDirectory.DOCUMENTS);
160 if (dir.contains ("/")) {
161 IconDirectory icon = {dir, Marlin.ICON_FOLDER_DOCUMENTS_SYMBOLIC, false, null, null, dir.split ("/"), false, null};
162 icon.exploded[0] = "/";
163 add_icon (icon);
164 }
165
166 dir = Environment.get_user_special_dir (UserDirectory.TEMPLATES);
167 if (dir.contains ("/")) {
168 IconDirectory icon = {dir, Marlin.ICON_FOLDER_TEMPLATES_SYMBOLIC, false, null, null, dir.split ("/"), false, null};
169 icon.exploded[0] = "/";
170 add_icon (icon);
171 }
172
173 dir = Environment.get_home_dir ();
174 if (dir.contains ("/")) {
175 IconDirectory icon = {dir, Marlin.ICON_GO_HOME_SYMBOLIC, false, null, null, dir.split ("/"), true, null};
176 icon.exploded[0] = "/";
177 add_icon (icon);
178 }
179
180
181 dir = "/media";
182 if (dir.contains ("/")) {
183 IconDirectory icon = {dir, Marlin.ICON_FILESYSTEM_SYMBOLIC, false, null, null, dir.split ("/"), true, null};
184 icon.exploded[0] = "/";
185 add_icon (icon);
186 }
187
188 IconDirectory icon = {"/", Marlin.ICON_FILESYSTEM_SYMBOLIC, false, null, null, null, false, null};
189 icon.exploded = {"/"};
190 add_icon (icon);
191
192 menu = new Gtk.Menu ();
193 menu.show_all ();
194 }
195
196 protected override void load_right_click_menu (double x, double y) {
197
198 }
199
200 protected override bool on_drag_motion (Gdk.DragContext context, int x, int y, uint time) {
201 Gtk.drag_unhighlight (this);
202
203 foreach (BreadcrumbsElement element in elements)
204 element.pressed = false;
205
206 var el = get_element_from_coordinates (x, y);
207
208 if (el != null)
209 el.pressed = true;
210 else
211 /* No action taken on drop */
212 Gdk.drag_status (context, 0, time);
213
214 queue_draw ();
215
216 return false;
217 }
218
219 protected override bool on_drag_drop (Gdk.DragContext context,
220 int x,
221 int y,
222 uint timestamp) {
223 Gtk.TargetList list = null;
224 bool ok_to_drop = false;
225
226 Gdk.Atom target = Gtk.drag_dest_find_target (this, context, list);
227
228 ok_to_drop = (target != Gdk.Atom.NONE);
229
230 if (ok_to_drop) {
231 drop_occurred = true;
232 Gtk.drag_get_data (this, context, target, timestamp);
233 }
234
235 return ok_to_drop;
236 }
237
238 protected override void on_drag_data_received (Gdk.DragContext context,
239 int x,
240 int y,
241 Gtk.SelectionData selection_data,
242 uint info,
243 uint timestamp) {
244 bool success = false;
245
246 if (!drop_data_ready) {
247 drop_file_list = null;
248 foreach (var uri in selection_data.get_uris ()) {
249 debug ("Path to move: %s\n", uri);
250 drop_file_list.append (File.new_for_uri (uri));
251 drop_data_ready = true;
252 }
253 }
254
255 if (drop_data_ready && drop_occurred && info == TargetType.TEXT_URI_LIST) {
256 drop_occurred = false;
257 current_actions = 0;
258 current_suggested_action = 0;
259
260 Gtk.drag_finish (context, success, false, timestamp);
261 on_drag_leave (context, timestamp);
262 }
263 }
264
265 protected override void on_drag_leave (Gdk.DragContext drag_context, uint time) {
266 foreach (BreadcrumbsElement element in elements) {
267 if (element.pressed) {
268 element.pressed = false;
269 break;
270 }
271 }
272
273 drop_occurred = false;
274 drop_data_ready = false;
275 drop_file_list = null;
276
277 queue_draw ();
278 }
279 }
280}
0281
=== added file 'filechooser-module/Plugin.vala'
--- filechooser-module/Plugin.vala 1970-01-01 00:00:00 +0000
+++ filechooser-module/Plugin.vala 2015-05-30 21:14:32 +0000
@@ -0,0 +1,57 @@
1// -*- Mode: vala; indent-tabs-mode: nil; tab-width: 4 -*-
2/*-
3 * Copyright (c) 2013 Pantheon Developers (http://launchpad.net/elementary)
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Library General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Library General Public License for more details.
14 *
15 * You should have received a copy of the GNU Library General Public
16 * License along with this library; if not, write to the
17 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 * Boston, MA 02111-1307, USA.
19 *
20 * Authored by: Corentin Noël <tintou@mailoo.org>
21 */
22
23public class PantheonModule.FileChooserDialog : GLib.Object {
24 /* Catching dialogs section by: tintou (https://launchpad.net/~tintou) */
25 Gee.TreeSet<Gtk.FileChooserDialog> tree_set;
26 public FileChooserDialog () {
27 tree_set = new Gee.TreeSet<Gtk.FileChooserDialog> ();
28 /* It's the only way to get every new window */
29 var map_id = GLib.Signal.lookup ("window-state-event", typeof (Gtk.Dialog));
30 GLib.Signal.add_emission_hook (map_id, 0, (ihint, param_values) => {
31 if (param_values[0].type () == typeof (Gtk.FileChooserDialog)) {
32 var dialog = (Gtk.FileChooserDialog)param_values [0];//.dup_object ();
33 if (tree_set.contains (dialog) == false) {
34 tree_set.add (dialog);
35
36 var dialog_new = new CustomFileChooserDialog (dialog);
37 dialog_new.set_open_path (dialog.get_current_folder ());
38 dialog.destroy.connect (() => {
39 tree_set.remove (dialog);
40 });
41 }
42 }
43
44 return true;
45 }, null);
46 }
47}
48
49public static PantheonModule.FileChooserDialog filechooser_module = null;
50public void gtk_module_init ([CCode (array_length_cname = "argc", array_length_pos = 0.5)] ref unowned string[]? argv) {
51 if (Gtk.check_version (3, 14, 0) == null) {
52 var appinfo = AppInfo.get_default_for_type ("inode/directory", true);
53 if (appinfo.get_executable () == "pantheon-files")
54 filechooser_module = new PantheonModule.FileChooserDialog ();
55 } else
56 warning ("The required GTK version is 3.14");
57}
0\ No newline at end of file58\ No newline at end of file

Subscribers

People subscribed via source and target branches

to all changes: