2 * This file is part of RawTherapee.
4 * Copyright (c) 2004-2010 Gabor Horvath <hgabor@rawtherapee.com>
6 * RawTherapee is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
11 * RawTherapee is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with RawTherapee. If not, see <http://www.gnu.org/licenses/>.
19 #include <dirbrowser.h>
21 #define _WIN32_WINNT 0x0600
27 #define CHECKTIME 5000
28 extern Glib::ustring argv0
;
30 DirBrowser::DirBrowser () {
32 dirtree
= new Gtk::TreeView();
33 scrolledwindow4
= new Gtk::ScrolledWindow();
35 // dirtree->set_flags(Gtk::CAN_FOCUS);
36 dirtree
->set_headers_visible(false);
37 dirtree
->set_rules_hint(false);
38 dirtree
->set_reorderable(false);
39 dirtree
->set_enable_search(false);
40 scrolledwindow4
->set_flags(Gtk::CAN_FOCUS
);
41 scrolledwindow4
->set_border_width(2);
42 scrolledwindow4
->set_shadow_type(Gtk::SHADOW_NONE
);
43 scrolledwindow4
->set_policy(Gtk::POLICY_ALWAYS
, Gtk::POLICY_ALWAYS
);
44 scrolledwindow4
->property_window_placement().set_value(Gtk::CORNER_TOP_LEFT
);
45 scrolledwindow4
->add(*dirtree
);
47 pack_start (*scrolledwindow4
);
49 scrolledwindow4
->show ();
52 void DirBrowser::fillDirTree () {
54 openfolder
= Gdk::Pixbuf::create_from_file (GET_DATA_PATH(argv0
)+"/images/folder_open.png");
55 closedfolder
= Gdk::Pixbuf::create_from_file (GET_DATA_PATH(argv0
)+"/images/folder.png");
56 icdrom
= Gdk::Pixbuf::create_from_file (GET_DATA_PATH(argv0
)+"/images/cdrom.png");
57 ifloppy
= Gdk::Pixbuf::create_from_file (GET_DATA_PATH(argv0
)+"/images/floppy.png");
58 ihdd
= Gdk::Pixbuf::create_from_file (GET_DATA_PATH(argv0
)+"/images/hdd.png");
59 iremovable
= Gdk::Pixbuf::create_from_file (GET_DATA_PATH(argv0
)+"/images/usbpendrive.png");
60 inetwork
= Gdk::Pixbuf::create_from_file (GET_DATA_PATH(argv0
)+"/images/network.png");
62 //Create the Tree model:
63 dirTreeModel
= Gtk::TreeStore::create(dtColumns
);
64 dirtree
->set_model (dirTreeModel
);
68 Gtk::CellRendererPixbuf
* render_pb
= new Gtk::CellRendererPixbuf ();
69 tvc
.pack_start (*render_pb
, false);
70 tvc
.add_attribute(*render_pb
, "pixbuf-expander-closed", 1);
71 tvc
.add_attribute(*render_pb
, "pixbuf", 1);
72 tvc
.add_attribute(*render_pb
, "pixbuf-expander-open", 0);
74 tvc
.add_attribute(crt
, "text", 2);
76 crt
.property_ypad() = 0;
77 render_pb
->property_ypad() = 0;
79 dirtree
->append_column(tvc
);
81 dirtree
->signal_row_expanded().connect(sigc::mem_fun(*this, &DirBrowser::row_expanded
));
82 dirtree
->signal_row_activated().connect(sigc::mem_fun(*this, &DirBrowser::row_activated
));
86 void DirBrowser::addRoot (char letter
) {
90 strcpy (volume
+1, ":\\");
92 Gtk::TreeModel::iterator root
= dirTreeModel
->append();
93 root
->set_value (dtColumns
.filename
, Glib::ustring(volume
));
94 root
->set_value (dtColumns
.dirname
, Glib::ustring(volume
));
96 int type
= GetDriveType (volume
);
97 if (type
==DRIVE_CDROM
) {
98 root
->set_value (0, icdrom
);
99 root
->set_value (1, icdrom
);
101 else if (type
==DRIVE_REMOVABLE
) {
103 root
->set_value (0, ifloppy
);
104 root
->set_value (1, ifloppy
);
107 root
->set_value (0, iremovable
);
108 root
->set_value (1, iremovable
);
111 else if (type
==DRIVE_REMOTE
) {
112 root
->set_value (0, inetwork
);
113 root
->set_value (1, inetwork
);
115 else if (type
==DRIVE_FIXED
) {
116 root
->set_value (0, ihdd
);
117 root
->set_value (1, ihdd
);
120 Gtk::TreeModel::iterator child
= dirTreeModel
->append (root
->children());
121 child
->set_value (dtColumns
.filename
, Glib::ustring("foo"));
124 void DirBrowser::updateDirTreeRoot () {
126 for (Gtk::TreeModel::iterator i
=dirTreeModel
->children().begin(); i
!=dirTreeModel
->children().end(); i
++)
130 void DirBrowser::updateDirTree (const Gtk::TreeModel::iterator
& iter
) {
132 if (dirtree
->row_expanded (dirTreeModel
->get_path (iter
))) {
134 for (Gtk::TreeModel::iterator i
=iter
->children().begin(); i
!=iter
->children().end(); i
++)
139 void DirBrowser::updateVolumes () {
141 int nvolumes
= GetLogicalDrives ();
142 if (nvolumes
!=volumes
) {
143 for (int i
=0; i
<32; i
++)
144 if (((volumes
>> i
) & 1) && !((nvolumes
>> i
) & 1)) { // volume i has been deleted
145 for (Gtk::TreeModel::iterator iter
= dirTreeModel
->children().begin(); iter
!=dirTreeModel
->children().end(); iter
++)
146 if (iter
->get_value (dtColumns
.filename
).c_str()[0]-'A' == i
) {
147 dirTreeModel
->erase (iter
);
151 else if (!((volumes
>> i
) & 1) && ((nvolumes
>> i
) & 1))
152 addRoot ('A'+i
); // volume i has been added
157 int _updateVolumes (void* br
) {
159 gdk_threads_enter ();
160 ((DirBrowser
*)br
)->updateVolumes ();
161 gdk_threads_leave ();
164 int _updateDirTree (void* br
) {
166 gdk_threads_enter ();
167 ((DirBrowser
*)br
)->updateDirTreeRoot ();
168 gdk_threads_leave ();
172 void DirBrowser::winDirChanged () {
174 g_idle_add (_updateDirTree
, this);
178 void DirBrowser::fillRoot () {
181 volumes
= GetLogicalDrives ();
182 for (int i
=0; i
<32; i
++)
183 if ((volumes
>> i
) & 1)
185 // since sigc++ is not thread safe, we have to use the glib function
186 g_timeout_add (CHECKTIME
, _updateVolumes
, this);
188 Gtk::TreeModel::Row rootRow
= *(dirTreeModel
->append());
189 rootRow
[dtColumns
.filename
] = "/";
190 rootRow
[dtColumns
.dirname
] = "/";
191 Gtk::TreeModel::Row childRow
= *(dirTreeModel
->append(rootRow
.children()));
192 childRow
[dtColumns
.filename
] = "foo";
196 void DirBrowser::row_expanded (const Gtk::TreeModel::iterator
& iter
, const Gtk::TreeModel::Path
& path
) {
198 expandSuccess
= false;
200 int todel
= iter
->children().size();
203 std::vector
<Glib::ustring
> subDirs
;
204 Glib::RefPtr
<Gio::File
> dir
= Gio::File::create_for_path (iter
->get_value (dtColumns
.dirname
));
207 Glib::RefPtr
<Gio::FileEnumerator
> dirList
= dir
->enumerate_children ();
209 for (Glib::RefPtr
<Gio::FileInfo
> info
= dirList
->next_file(); info
; info
= dirList
->next_file())
210 if (info
->get_file_type() == Gio::FILE_TYPE_DIRECTORY
&& (!info
->is_hidden() || options
.fbShowHidden
))
211 subDirs
.push_back (info
->get_name());
214 std::sort (subDirs
.begin(), subDirs
.end());
215 for (int i
=0; i
<subDirs
.size(); i
++)
216 addDir (iter
, subDirs
[i
]);
218 for (int i
=0; i
<todel
; i
++)
219 dirTreeModel
->erase (iter
->children().begin());
220 expandSuccess
= true;
222 Glib::RefPtr
<WinDirMonitor
> monitor
= Glib::RefPtr
<WinDirMonitor
>(new WinDirMonitor (iter
->get_value (dtColumns
.dirname
), this));
223 iter
->set_value (dtColumns
.monitor
, monitor
);
225 Glib::RefPtr
<Gio::FileMonitor
> monitor
= dir
->monitor_directory ();
226 iter
->set_value (dtColumns
.monitor
, monitor
);
227 monitor
->signal_changed().connect (sigc::bind(sigc::mem_fun(*this, &DirBrowser::file_changed
), iter
, dir
->get_parse_name()));
230 catch (Glib::Exception
&ex
) {
232 dirtree
->collapse_row (path
);
236 void DirBrowser::updateDir (const Gtk::TreeModel::iterator
& iter
) {
238 // first test if some files are deleted
242 for (Gtk::TreeModel::iterator it
=iter
->children().begin(); it
!=iter
->children().end(); it
++)
243 if (!Glib::file_test (it
->get_value (dtColumns
.dirname
), Glib::FILE_TEST_EXISTS
)
244 || !Glib::file_test (it
->get_value (dtColumns
.dirname
), Glib::FILE_TEST_IS_DIR
)) {
245 dirTreeModel
->erase (it
);
250 // test if new files are created
252 std::vector
<Glib::ustring
> subDirs
;
253 Glib::RefPtr
<Gio::File
> dir
= Gio::File::create_for_path (iter
->get_value (dtColumns
.dirname
));
256 Glib::RefPtr
<Gio::FileEnumerator
> dirList
= dir
->enumerate_children ();
257 for (Glib::RefPtr
<Gio::FileInfo
> info
= dirList
->next_file(); info
; info
= dirList
->next_file())
258 if (info
->get_file_type() == Gio::FILE_TYPE_DIRECTORY
&& (!info
->is_hidden() || options
.fbShowHidden
))
259 subDirs
.push_back (info
->get_name());
261 for (int i
=0; i
<subDirs
.size(); i
++) {
263 for (Gtk::TreeModel::iterator it
=iter
->children().begin(); it
!=iter
->children().end(); it
++)
264 if (it
->get_value (dtColumns
.filename
)==subDirs
[i
]) {
269 addDir (iter
, subDirs
[i
]);
272 catch (Glib::Exception
&ex
) {
277 void DirBrowser::addDir (const Gtk::TreeModel::iterator
& iter
, const Glib::ustring
& dirname
) {
279 Gtk::TreeModel::iterator child
= dirTreeModel
->append(iter
->children());
280 child
->set_value (dtColumns
.filename
, dirname
);
281 child
->set_value (0, openfolder
);
282 child
->set_value (1, closedfolder
);
283 Glib::ustring fullname
= Glib::build_filename (iter
->get_value (dtColumns
.dirname
), dirname
);
284 child
->set_value (dtColumns
.dirname
, fullname
);
285 Glib::RefPtr
<Gio::File
> f
= Gio::File::create_for_path (fullname
);
286 Gtk::TreeModel::iterator fooRow
= dirTreeModel
->append(child
->children());
287 fooRow
->set_value (dtColumns
.filename
, Glib::ustring("foo"));
290 void DirBrowser::row_activated (const Gtk::TreeModel::Path
& path
, Gtk::TreeViewColumn
* column
) {
292 Glib::ustring dname
= dirTreeModel
->get_iter (path
)->get_value (dtColumns
.dirname
);
293 if (Glib::file_test (dname
, Glib::FILE_TEST_IS_DIR
))
294 for (int i
=0; i
<dllisteners
.size(); i
++)
295 dllisteners
[i
]->dirSelected (dname
);
298 Gtk::TreePath
DirBrowser::expandToDir (const Glib::ustring
& absDirPath
) {
300 Gtk::TreeModel::Path path
;
301 path
.append_index(0);
305 char* dir
= new char [1024];
306 char* dcpy
= strdup (absDirPath
.c_str());
307 dir
= strtok (dcpy
, "/\\");
309 expandSuccess
= true;
312 Gtk::TreeModel::iterator j
= dirTreeModel
->get_iter (path
);
314 path
.append_index (0);
315 row_expanded(j
, path
);
316 path
.append_index (0);
320 Glib::ustring dirstr
= dir
;
323 dirstr
= dirstr
+ "\\";
325 Gtk::TreeModel::iterator i
= dirTreeModel
->get_iter (path
);
327 while (i
&& expandSuccess
) {
328 Gtk::TreeModel::Row crow
= *i
;
329 Glib::ustring str
=crow
[dtColumns
.filename
];
331 if (str
.casefold()==dirstr
.casefold()) {
336 path
.append_index (ix
);
337 row_expanded(i
, path
);
338 path
.append_index (0);
345 dir
= strtok(NULL
, "/\\");
352 dirtree
->expand_to_path (path
);
357 void DirBrowser::open (const Glib::ustring
& dirname
, const Glib::ustring
& fileName
) {
359 dirtree
->collapse_all ();
361 Glib::ustring absDirPath
= Gio::File::create_for_path(dirname
)->get_parse_name ();
362 Gtk::TreePath path
= expandToDir (absDirPath
);
365 dirtree
->scroll_to_row (path
);
366 dirtree
->get_selection()->select (path
);
367 for (int i
=0; i
<dllisteners
.size(); i
++)
368 dllisteners
[i
]->dirSelected (absDirPath
, Glib::build_filename (absDirPath
, fileName
));
372 void DirBrowser::file_changed (const Glib::RefPtr
<Gio::File
>& file
, const Glib::RefPtr
<Gio::File
>& other_file
, Gio::FileMonitorEvent event_type
, const Gtk::TreeModel::iterator
& iter
, const Glib::ustring
& dirName
) {
374 if (!file
|| !Glib::file_test (dirName
, Glib::FILE_TEST_IS_DIR
) || event_type
==Gio::FILE_MONITOR_EVENT_ATTRIBUTE_CHANGED
)
381
void DirBrowser::selectDir (Glib::ustring dir
) {