2009-06-17 Jeffrey Stedfast <fejj@novell.com>
[moon.git] / src / openfile.cpp
bloba99950c9a3de75fb033ea63b3af774e457ffc11d
1 /*
2 * openfile.cpp: File Access and I/O
4 * Contact:
5 * Moonlight List (moonlight-list@lists.ximian.com)
7 * Copyright 2007, 2009 Novell, Inc. (http://www.novell.com)
9 * See the LICENSE file included with the distribution for details.
13 #include <config.h>
14 #include "openfile.h"
16 // FIXME: Silverlight 1.1 (alpha, refresh) doesn't allow the selection(*) of
17 // symlinks on Mac OSX. (*) actually it de-selects them on the fly. We should
18 // be able to duplicate this with lstat and the selection-changed event.
20 static void
21 set_filters (GtkFileChooser *chooser, const char* filter, int idx)
23 if (!filter || (strlen (filter) <= 1))
24 return;
26 char **filters = g_strsplit (filter, "|", 0);
28 // to be valid (managed code) we know we have an even number of items
29 // (if not we're still safe by dropping the last one)
30 int pos = 0;
31 int n = g_strv_length (filters) >> 1;
32 for (int i=0; i < n; i++) {
33 char *name = g_strstrip (filters[pos++]);
34 if (strlen (name) < 1)
35 continue;
37 char *pattern = g_strstrip (filters[pos++]);
38 if (strlen (pattern) < 1)
39 continue;
41 GtkFileFilter *ff = gtk_file_filter_new ();
42 gtk_file_filter_set_name (ff, g_strdup (name));
43 // there can be multiple patterns in a single string
44 if (g_strrstr (pattern, ";")) {
45 int n = 0;
46 char **patterns = g_strsplit (pattern, ";", 0);
47 while (char *p = patterns[n++])
48 gtk_file_filter_add_pattern (ff, g_strdup (p));
49 g_strfreev (patterns);
50 } else {
51 // or a single one
52 gtk_file_filter_add_pattern (ff, g_strdup (pattern));
54 gtk_file_chooser_add_filter (chooser, ff);
55 // idx (FilterIndex) is 1 (not 0) based
56 if (i == (idx - 1))
57 gtk_file_chooser_set_filter (chooser, ff);
59 g_strfreev (filters);
62 char **
63 open_file_dialog_show (const char *title, bool multsel, const char *filter, int idx)
65 GtkWidget *widget = gtk_file_chooser_dialog_new (title, NULL,
66 GTK_FILE_CHOOSER_ACTION_OPEN,
67 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
68 GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT, NULL);
70 GtkFileChooser *chooser = GTK_FILE_CHOOSER (widget);
71 set_filters (chooser, filter, idx);
72 gtk_file_chooser_set_select_multiple (chooser, multsel ? TRUE : FALSE);
74 char **ret = NULL;
75 if (gtk_dialog_run (GTK_DIALOG (widget)) == GTK_RESPONSE_ACCEPT){
76 GSList *k, *l = gtk_file_chooser_get_filenames (chooser);
77 int i, count = g_slist_length (l);
79 ret = g_new (char *, count + 1);
80 ret [count] = NULL;
82 for (i = 0, k = l; k; k = k->next)
83 ret [i++] = (char *) k->data;
85 g_slist_free (l);
88 gtk_widget_destroy (widget);
90 return ret;
93 char *
94 save_file_dialog_show (const char *title, const char *filter, int idx)
96 GtkWidget *widget = gtk_file_chooser_dialog_new (title, NULL,
97 GTK_FILE_CHOOSER_ACTION_SAVE,
98 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
99 GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT, NULL);
101 GtkFileChooser *chooser = GTK_FILE_CHOOSER (widget);
102 set_filters (chooser, filter, idx);
103 gtk_file_chooser_set_do_overwrite_confirmation (chooser, TRUE);
105 char *ret = NULL;
106 if (gtk_dialog_run (GTK_DIALOG (widget)) == GTK_RESPONSE_ACCEPT)
107 ret = gtk_file_chooser_get_filename (chooser);
109 gtk_widget_destroy (widget);
111 return ret;
114 // NOTE: this is used from 'mscorlib.dll' System.IO.IsolatedStorage/MoonIsolatedStorageFile.cs
115 // NOTE: we let the caller supply the string so i18n can occur in managed land only
116 gboolean
117 isolated_storage_increase_quota_to (const char *primary_text, const char* secondary_text)
119 // the dialog is displayed only if the action leading to this call was initiated directly from the user
120 if (!Deployment::GetCurrent ()->GetSurface ()->IsUserInitiatedEvent ())
121 return false;
123 GtkWidget *widget = gtk_message_dialog_new_with_markup (NULL,
124 GTK_DIALOG_MODAL,
125 GTK_MESSAGE_QUESTION,
126 GTK_BUTTONS_YES_NO,
127 primary_text);
129 gtk_window_set_title (GTK_WINDOW (widget), PACKAGE_STRING);
130 gtk_message_dialog_format_secondary_markup (GTK_MESSAGE_DIALOG (widget), secondary_text);
132 gboolean result = (gtk_dialog_run (GTK_DIALOG (widget)) == GTK_RESPONSE_YES);
133 gtk_widget_destroy (widget);
134 return result;
137 // recursively calculate the size of the specified directory
138 static long
139 get_size (const char *root)
141 // NOTE: just like Silverlight we give a minimum cost of 1KB for each
142 // directory and file to avoid disk exhaustion by empty files/directories.
143 long result = MOONLIGHT_MINIMUM_FILE_ENTRY_COST;
144 struct stat info;
145 if (g_lstat (root, &info) != 0)
146 return result;
148 // there should be no link in IS but, if any, we're not following them
149 if (S_ISLNK (info.st_mode))
150 return result;
152 if (S_ISDIR (info.st_mode)) {
153 // scan everythins inside the directory
154 GDir *dir = g_dir_open (root, 0, NULL);
155 if (!dir)
156 return result; // should never happen
158 // note: g_dir_read_name *smartly* skips '.' and '..'
159 const char *entry_name = g_dir_read_name (dir);
160 while (entry_name) {
161 char name [PATH_MAX];
162 if (g_snprintf (name, PATH_MAX, "%s/%s", root, entry_name) <= PATH_MAX)
163 result += get_size (name);
165 entry_name = g_dir_read_name (dir);
167 g_dir_close (dir);
168 } else {
169 // file size is computed at 1KB boundaries, minimum of 1KB (fixed cost for a file-system entry)
170 result = (info.st_size & ~MOONLIGHT_FILE_SIZE_MASK);
171 if ((result == 0) || (info.st_size & MOONLIGHT_FILE_SIZE_MASK))
172 result += MOONLIGHT_MINIMUM_FILE_ENTRY_COST;
175 return result;
178 // NOTE: this is used from 'mscorlib.dll' System.IO.IsolatedStorage/MoonIsolatedStorage.cs
179 long
180 isolated_storage_get_current_usage (const char* root)
182 // XXX we should cache the value and invalidate it if something changed (e.g. using inotify)
183 return get_size (root);