-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy pathxcd.pro
382 lines (369 loc) · 11.5 KB
/
xcd.pro
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
;+
; NAME:
; xcd
;
; PURPOSE:
; Change current directory via mouse.
;
; Two lists are displayed side by side. The one on the left shows
; directories. Click on a directory to cd there. The list
; on the right shows files to help you see where you are.
; (The list on the right does not respond to mouse clicks.)
; CATEGORY:
; Utility.
; CALLING SEQUENCE:
; xcd
; INPUTS:
; None.
; KEYWORD PARAMETERS:
; None
; OUTPUTS:
; None.
; SIDE EFFECTS:
; Your current directory can be changed.
; RESTRICTIONS:
; Windows & OpenVMS platforms only. Originally written on Windows95.
; Should work on other Windows platforms, but I (Paul) havn't tried it.
;
; With a little effort, one probably could port Xcd to other platforms
; (i.e. Unix or Mac).
;
; Note that drive names (e.g. "a:", "c:", etc.) are hardcoded in
; xcd::init. Change that line of code to show drive letters
; appropriate for your system.
;
; PROCEDURE:
; Xcd creates an object that has a reference to a DirListing, and
; widgets for displaying that DirListing. If the user clicks on a
; sub-directory (or "..\") in the xcd object, or droplist-selects
; a different drive via the xcd object, the xcd object changes
; IDL's current directory to that location, and refreshes with a
; new current-directory DirListing.
;
; MODIFICATION HISTORY:
; Paul C. Sorenson, July 1997. [email protected].
; Written with IDL 5.0. The object-oriented design of Xcd is
; based in part on an example authored by Mark Rivers.
; Jim Pendleton, July 1997. [email protected]
; Modified for compatability with OpenVMS as a basis for
; platform independent code
; Paul C. Sorenson, July 13 1997. Changes so that DirListing class
; methods do not return pointers to data members. (Better
; object-oriented design that way.)
;
;-
function dirlisting::init, location
;
;Function DirListing::INIT: construct listing of LOCATION's contents.
;INPUT:
; LOCATION (optional): string indicating the directory we want listing
; of. default is current directory.
;
catch, error_stat
if error_stat ne 0 then begin
print, !err_string
return, 0
end
;
;Store name of location.
;
if n_elements(location) gt 0 then $
pushd, location
cd, current=current
case !version.os_family of
'Windows' : begin
self.Drive = strmid(current, 0, 2)
self.Path = strmid(current, 2, strlen(current))
end
'vms' : begin
colon = rstrpos(current, ':')
self.Drive = strmid(current, 0, colon + 1)
rightbracket = rstrpos(current, ']')
self.Path = strmid(current, colon + 1, rightbracket - colon)
end
else :
endcase
;
;Obtain listing of location's contents.
;
listing = Findfile()
;listing = File_Search('*')
if n_elements(location) gt 0 then $
popd
;
;Divide into direcory-only & file-only listings.
;
flags = bytarr(n_elements(listing))
case !version.os_family of
'Windows' : begin
for i=0,n_elements(listing)-1 do begin
if rstrpos(listing[i], '\') eq (strlen(listing[i]) - 1) then $
flags[i] = 1b
end
end
'vms' : begin
for i=0,n_elements(listing)-1 do begin
dotdir = strpos(listing[i], '.DIR;')
if dotdir ne -1 then begin
flags[i] = 1b
rightbracket = rstrpos(listing[i], ']')
listing[i] = strmid(listing[i], rightbracket + 1, $
dotdir - rightbracket - 1)
end
end
end
else :
endcase
dirs_indx = where(flags, dir_count)
files_indx = where(flags eq 0b, file_count)
if dir_count gt 0 then begin
dirs = listing[dirs_indx]
case !version.os_family of
'Windows' : begin
dirs = dirs[where(dirs ne '.\')]
end
'vms' :
else :
endcase
dirs = dirs[sort(strupcase(dirs))]
if (!version.os_family eq 'vms') then $
dirs = ['[-]', 'sys$login', dirs]
end $
else begin
if (!version.os_family eq 'vms') then begin
dirs = ['[-]', 'sys$login']
end $
else begin
dirs = ''
end
end
if file_count gt 0 then begin
files = listing[files_indx]
case !version.os_family of
'Windows' : files = files[sort(strupcase(files))]
'vms' : begin
for i = 0l, n_elements(files) - 1 do begin
rightbracket = rstrpos(files[i], ']')
files[i] = strmid(files[i], rightbracket + 1, $
strlen(files[i]))
end
files = files[sort(strupcase(files))]
end
endcase
end $
else begin
files = ''
end
;
;Store pointers to resulting string arrays.
;
self.pSubdirNames = ptr_new(dirs, /no_copy)
self.pFileNames = ptr_new(files, /no_copy)
return, 1 ; Success.
end
;----------------------------------------------------------------------
pro dirlisting::cleanup
ptr_free, self.pSubdirNames
ptr_free, self.pFileNames
end
;----------------------------------------------------------------------
pro dirlisting__define
void = {dirlisting, $
Drive: '', $ ; e.g. 'c:'
Path: '', $ ; location. e.g. '\foo\bar'
pSubdirNames: ptr_new(), $ ; string array of sub-directory names
pFileNames: ptr_new() $ ; string array of file names
}
end
;----------------------------------------------------------------------
function dirlisting::SubdirNames
return, *self.pSubdirNames
end
;----------------------------------------------------------------------
function dirlisting::FileNames
return, *self.pFileNames
end
;----------------------------------------------------------------------
function dirlisting::Path
return, self.Path
end
;----------------------------------------------------------------------
function dirlisting::Drive
return, self.Drive
end
;----------------------------------------------------------------------
pro xcd::handle, event
catch, error_stat
if error_stat ne 0 then begin
catch, /cancel
void = dialog_message(!err_string, /error)
self->update ; Try again, this time without "cd".
return
end
case event.id of
self.wDirList: begin
path = self.rDirListing->Path()
;
; Construct full (if possible) pathname, and cd to it. (Using
; a full, rather than relative, pathname here makes xcd impervious
; to directory changes made by other IDL programs or from the
; command line.)
;
case !version.os_family of
'Windows' : begin
if rstrpos(path, '\') ne (strlen(path) - 1) then $
path = path + '\'
cd, self.rDirListing->Drive() $
+ path $
+ (self.rDirListing->SubdirNames())[event.index]
end
'vms' : begin
subdir = (self.rDirListing->SubdirNames())[event.index]
if (subdir ne '[-]' and subdir ne 'sys$login') then begin
rightbracket = rstrpos(path, ']')
leftbracket = strpos(path, '[')
path = strmid(path, leftbracket + 1, rightbracket - $
leftbracket - 1)
newdir = self.rDirListing->Drive() $
+ '[' + path + '.' $
+ subdir + ']'
end $
else begin
newdir = subdir
end
cd, newdir
end
else:
endcase
;
self->update
widget_control, self.tlb, /update ; workaround. Resize base.
end
self.wDriveList: begin
widget_control, /hourglass
case !version.os_family of
'Windows' : cd, (*self.pDriveNames)[event.index]
'vms' : cd, (*self.pDriveNames)[event.index] + '[000000]'
else:
endcase
self->update
widget_control, self.tlb, /update ; workaround. Resize base.
end
else: begin
end
endcase
end
;----------------------------------------------------------------------
pro xcd_cleanup, tlb
widget_control, tlb, get_uvalue=rXcd ; get a reference to Xcd.
obj_destroy, rXcd
end
;----------------------------------------------------------------------
pro xcd::cleanup
obj_destroy, self.rDirListing
ptr_free, self.pDriveNames
cd, current=current & print, current
end
;----------------------------------------------------------------------
pro xcd_event, event
widget_control, event.top, get_uvalue=rXcd
rXcd->handle, event
end
;----------------------------------------------------------------------
pro xcd::update
;
;Procedure XCD::UPDATE: set self's widgets and state values to
; reflect the current directory.
;
widget_control, /hourglass
obj_destroy, self.rDirListing
self.rDirListing = obj_new('dirlisting')
rDirListing = self.rDirListing
indx = where(strupcase(*self.pDriveNames) eq $
strupcase(rDirListing->Drive()))
widget_control, self.wDriveList, set_droplist_select=indx(0)
widget_control, self.wLabel, set_value=rDirListing->Path()
widget_control, self.wDirList, set_value=rDirListing->SubdirNames()
widget_control, self.wFileList, set_value=rDirListing->FileNames()
end
;----------------------------------------------------------------------
function xcd::init
catch, error_status
if error_status ne 0 then begin
print, !err_string
return, 0
end
case !version.os_family of
'Windows' : begin
;CHANGE THESE HARDCODED DRIVENAMES TO SUIT YOUR SYSTEM.
self.pDriveNames = ptr_new(['a:', 'c:', 'd:', 'e', 'f', 'g:', 'h:', 'i'])
end
'vms' : begin
openw, lun, 'sys$scratch:idl_xcdtmp.tmp', /get_lun
printf, lun, '$ loop:'
printf, lun, '$ disk = f$device("*", "DISK")'
printf, lun, '$ if (disk .nes. "")'
printf, lun, '$ then'
printf, lun, '$ write sys$output disk'
printf, lun, '$ goto loop'
printf, lun, '$ endif'
printf, lun, '$ delete/nolog/noconfirm sys$scratch:idl_xcdtmp.tmp;*'
free_lun, lun
spawn, '@sys$scratch:idl_xcdtmp.tmp', drives
self.pDriveNames = ptr_new(drives)
end
else:
endcase
;
;Create widgets.
;
tlb = widget_base(title='xcd', /column) ; top-level base
readout_base = widget_base(tlb, /row)
self.wDriveList = widget_droplist(readout_base, value=*self.pDriveNames)
self.wLabel = widget_label(readout_base, /dynamic_resize)
list_base = widget_base(tlb, /row)
ysize = 20 ; Looks good on my (Paul's) monitor.
self.wDirList = widget_list(list_base, ysize=ysize)
self.wFileList = widget_list(list_base, ysize=ysize)
;
;Set values.
;
self->update
self.tlb = tlb
widget_control, tlb, set_uvalue=self
;
;Center and realize tlb.
;
device, get_screen_size=scrsz
widget_control, tlb, map=0
widget_control, tlb, /realize
tlb_geometry = widget_info(tlb, /geometry)
widget_control, tlb, $
tlb_set_xoffset= 0 > (scrsz(0) - tlb_geometry.scr_xsize) / 2, $
tlb_set_yoffset= 0 > (scrsz(1) - tlb_geometry.scr_ysize) / 2
widget_control, tlb, map=1
widget_control, tlb, /update ; workaround. Resize base.
;
xmanager, 'xcd', tlb, cleanup='xcd_cleanup', /just_reg, /no_block
return, 1 ; Success.
end
;----------------------------------------------------------------------
pro xcd__define
void = {xcd, $
tlb: 0L, $ ; top-level base
wDriveList: 0L, $ ; droplist of available drives.
wLabel: 0L, $ ; shows name of current directory
wDirList: 0L, $ ; shows sub-directories in current directory
wFileList: 0L, $ ; shows files in current directory
pDriveNames: ptr_new(),$; String array. e.g. ['c:', 'd:', etc.]
rDirListing: obj_new() $; listing of current directory
}
end
;----------------------------------------------------------------------
pro xcd
;
on_error, 2 ; Return to caller if error.
if obj_new('xcd') eq obj_new() then $
message, 'failed to create xcd object.'
xmanager
end