1 /*
2 * R : A Computer Language for Statistical Data Analysis
3 * file selectlist.c
4 * Copyright (C) 1998--2003 Guido Masarotto and Brian Ripley
5 * Copyright (C) 2004 The R Foundation
6 * Copyright (C) 2005--2020 The R Core Team
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, a copy is available at
20 * https://www.R-project.org/Licenses/
21 */
22
23 #ifdef HAVE_CONFIG_H
24 #include <config.h>
25 #endif
26
27 #include <Defn.h>
28 #include "graphapp/ga.h"
29 #include <rui.h> // RConsole
30 #include <windows.h>
31
32 #include "win-nls.h"
33
34 static window wselect;
35 static button bFinish, bCancel;
36 static listbox f_list;
37 static int done;
38
cleanup(void)39 static void cleanup(void)
40 {
41 hide(wselect);
42 delobj(f_list); delobj(bFinish); delobj(bCancel);
43 delobj(wselect);
44 }
45
46
cancel(button b)47 static void cancel(button b)
48 {
49 done = 2;
50 }
51
finish(button b)52 static void finish(button b)
53 {
54 done = 1;
55 }
56
key1(control c,int ch)57 static void key1(control c, int ch)
58 {
59 if(ch == '\n') finish(NULL);
60 if(ch == ESC) cancel(NULL);
61 }
62
63 rect getSysFontSize(void); /* in graphapp/fonts.c */
64 RECT *RgetMDIsize(void); /* in rui.c */
65
Win_selectlist(SEXP args)66 SEXP Win_selectlist(SEXP args)
67 {
68 SEXP choices, preselect, ans = R_NilValue;
69 const char **clist;
70 int i, j = -1, n, mw = 0, multiple, nsel = 0;
71 int xmax, ymax, ylist, fht, h0;
72 Rboolean haveTitle;
73
74 choices = CAR(args);
75 if(!isString(choices)) error(_("invalid '%s' argument"), "choices");
76 preselect = CADR(args);
77 if(!isNull(preselect) && !isString(preselect))
78 error(_("invalid '%s' argument"), "preselect");
79 multiple = asLogical(CADDR(args));
80 if(multiple == NA_LOGICAL) multiple = 0;
81 haveTitle = isString(CADDDR(args));
82 if(!multiple && isString(preselect) && LENGTH(preselect) != 1)
83 error(_("invalid '%s' argument"), "preselect");
84
85 n = LENGTH(choices);
86 clist = (const char **) R_alloc(n + 1, sizeof(char *));
87 for(i = 0; i < n; i++) {
88 clist[i] = translateChar(STRING_ELT(choices, i));
89 mw = max(mw, gstrwidth(NULL, SystemFont, clist[i]));
90 }
91 clist[n] = NULL;
92
93 fht = getSysFontSize().height;
94
95 xmax = max(170, mw+60); /* allow for scrollbar */
96 if(ismdi()) {
97 RECT *pR = RgetMDIsize();
98 h0 = pR->bottom;
99 } else {
100 h0 = deviceheight(NULL);
101 }
102 ymax = min(80+fht*n, h0-100); /* allow for window widgets, toolbar */
103 ylist = ymax - 60;
104 wselect = newwindow(haveTitle ? translateChar(STRING_ELT(CADDDR(args), 0)):
105 (multiple ? _("Select one or more") : _("Select one")),
106 rect(0, 0, xmax, ymax),
107 Titlebar | Centered | Modal | Floating);
108 setbackground(wselect, dialog_bg());
109 if(multiple)
110 f_list = newmultilist(clist, rect(10, 10, xmax-25, ylist), NULL, finish);
111 else
112 f_list = newlistbox(clist, rect(10, 10, xmax-25, ylist), NULL, finish);
113 if(!isNull(preselect) && LENGTH(preselect)) {
114 for(i = 0; i < n; i++)
115 for(j = 0; j < LENGTH(preselect); j++)
116 if(strcmp(clist[i], translateChar(STRING_ELT(preselect, j))) == 0) {
117 setlistitem(f_list, i);
118 break;
119 }
120 }
121 bFinish = newbutton(G_("OK"), rect(xmax-160, ymax-40, 70, 25), finish);
122 bCancel = newbutton(G_("Cancel"), rect(xmax-80, ymax-40, 70, 25), cancel);
123 setkeydown(wselect, key1);
124 show(wselect);
125 done = 0;
126 while(!done) {
127 R_WaitEvent();
128 R_ProcessEvents();
129 }
130
131 if(multiple) {
132 if (done == 1) { /* Finish */
133 for(i = 0; i < n; i++) if(isselected(f_list, i)) nsel++;
134 PROTECT(ans = allocVector(STRSXP, nsel));
135 for(i = 0, j = 0; i < n; i++)
136 if(isselected(f_list, i))
137 SET_STRING_ELT(ans, j++, mkChar(clist[i]));
138 } else { /* cancel */
139 PROTECT(ans = allocVector(STRSXP, 0));
140 }
141 } else {
142 if (done == 1) { /* Finish */
143 i = getlistitem(f_list);
144 if (i >= 0)
145 PROTECT(ans = mkString(clist[i]));
146 else
147 PROTECT(ans = mkString("")); /* error/unreachable */
148 } else { /* cancel */
149 PROTECT(ans = mkString(""));
150 }
151 }
152
153 cleanup();
154 show(RConsole);
155 R_ProcessEvents();
156 UNPROTECT(1);
157 return ans;
158 }
159
countFilenamesW(const wchar_t * list)160 static int countFilenamesW(const wchar_t *list)
161 {
162 const wchar_t *temp;
163 int count;
164 count = 0;
165 for (temp = list; *temp; temp += wcslen(temp)+1) count++;
166 return count;
167 }
168
169
mkCharUTF8(const wchar_t * wc)170 static SEXP mkCharUTF8(const wchar_t *wc)
171 {
172 char s[4*MAX_PATH + 1];
173 wcstoutf8(s, wc, sizeof(s));
174 return mkCharCE(s, CE_UTF8);
175 }
176
177
chooseFiles(SEXP def,SEXP caption,SEXP smulti,SEXP filters,SEXP sindex)178 SEXP chooseFiles(SEXP def, SEXP caption, SEXP smulti, SEXP filters, SEXP sindex)
179 {
180 wchar_t *temp, *res, *cfilters;
181 const wchar_t *p;
182 wchar_t path[32768], filename[32768];
183 int multi, filterindex, i, count, lfilters, pathlen;
184
185 multi = asLogical(smulti);
186 filterindex = asInteger(sindex);
187 if(length(def) != 1 )
188 error(_("'default' must be a character string"));
189 p = filenameToWchar(STRING_ELT(def, 0), 1);
190 if(wcslen(p) >= 32768) error(_("'default' is overlong"));
191 wcscpy(path, p);
192 for(temp = path; *temp; temp++) if(*temp == L'/') *temp = L'\\';
193 if(length(caption) != 1 )
194 error(_("'caption' must be a character string"));
195 if(multi == NA_LOGICAL)
196 error(_("'multi' must be a logical value"));
197 if(filterindex == NA_INTEGER)
198 error(_("'filterindex' must be an integer value"));
199 lfilters = 1 + length(filters);
200 for (i = 0; i < length(filters); i++)
201 lfilters += wcslen(filenameToWchar(STRING_ELT(filters, i), 0));
202 cfilters = (wchar_t *) R_alloc(lfilters, sizeof(wchar_t));
203 temp = cfilters;
204 for (i = 0; i < length(filters)/2; i++) {
205 wcscpy(temp, filenameToWchar(STRING_ELT(filters, i), 0));
206 temp += wcslen(temp)+1;
207 wcscpy(temp, filenameToWchar(STRING_ELT(filters, i+length(filters)/2),
208 0));
209 temp += wcslen(temp)+1;
210 }
211 *temp = 0;
212
213 res = askfilenamesW(filenameToWchar(STRING_ELT(caption, 0), 0), path,
214 multi, cfilters, filterindex, NULL);
215
216 if (multi)
217 count = countFilenamesW(res);
218 else
219 count = wcslen(res) ? 1 : 0;
220
221 SEXP ans;
222 if (count < 2) PROTECT(ans = allocVector(STRSXP, count));
223 else PROTECT(ans = allocVector(STRSXP, count-1));
224
225 switch (count) {
226 case 0: break;
227 case 1: SET_STRING_ELT(ans, 0, mkCharUTF8(res));
228 break;
229 default:
230 wcsncpy(path, res, 32768);
231 pathlen = wcslen(path);
232 if (path[pathlen-1] == L'\\') path[--pathlen] = L'\0';
233 temp = res;
234 for (i = 0; i < count-1; i++) {
235 temp += wcslen(temp) + 1;
236 if (wcschr(temp,L':') || *temp == L'\\' || *temp == L'/')
237 SET_STRING_ELT(ans, i, mkCharUTF8(temp));
238 else {
239 wcsncpy(filename, path, 32768);
240 filename[pathlen] = L'\\';
241 wcsncpy(filename+pathlen+1, temp, 32768-pathlen-1);
242 SET_STRING_ELT(ans, i, mkCharUTF8(filename));
243 }
244 }
245 }
246 UNPROTECT(1);
247 return ans;
248 }
249
chooseDir(SEXP def,SEXP caption)250 SEXP chooseDir(SEXP def, SEXP caption)
251 {
252 const char *p;
253 char path[MAX_PATH];
254
255 if(!isString(def) || length(def) != 1 )
256 error(_("'default' must be a character string"));
257 p = translateChar(STRING_ELT(def, 0));
258 if(strlen(p) >= MAX_PATH) error(_("'default' is overlong"));
259 strcpy(path, R_ExpandFileName(p));
260 R_fixbackslash(path);
261 if(!isString(caption) || length(caption) != 1 )
262 error(_("'caption' must be a character string"));
263 p = askcdstring(translateChar(STRING_ELT(caption, 0)), path);
264
265 SEXP ans = PROTECT(allocVector(STRSXP, 1));
266 SET_STRING_ELT(ans, 0, p ? mkChar(p): NA_STRING);
267 UNPROTECT(1);
268 return ans;
269 }
270