00001 # Copyright (C) 1997-2004 The CDG Team <cdg@nats.informatik.uni-hamburg.de> 00002 # 00003 # This file is free software; as a special exception the author gives 00004 # unlimited permission to copy and/or distribute it, with or without 00005 # modifications, as long as this notice is preserved. 00006 # 00007 # This program is distributed in the hope that it will be useful, but 00008 # WITHOUT ANY WARRANTY, to the extent permitted by law; without even the 00009 # implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 00010 00011 ## ---------------------------------------------------------------------------- 00012 ## VisDirectory - a directory browser 00013 ## 00014 ## \author Michael Daum 00015 ## 00016 ## $Id: VisDirectory.tcl,v 1.10 2004/02/25 14:42:09 micha Exp $ 00017 ## ---------------------------------------------------------------------------- 00018 class VisDirectory { 00019 inherit iwidgets::Scrolledcanvas 00020 00021 # -- variables ------------------------------------------------------------- 00022 public variable chdircommand "" 00023 public variable selectioncommand "" 00024 public variable finishcommand "" 00025 00026 private variable _fileObjects {} 00027 private variable _selectedFiles {} 00028 private variable _maxWidth 70 00029 private variable _maxHeight 0 00030 private variable _filter "*" 00031 private variable _showHidden 1 00032 private variable _selectionAnchor "" 00033 private variable _browseMode "multi" 00034 private variable _fileMode "both" 00035 private variable _doneFlag 0 00036 00037 # -- methods --------------------------------------------------------------- 00038 public method show {dirName}; ## \type TclString 00039 public method hide {} 00040 public method getMaxFileWidth {} 00041 public method getMaxFileHeight {} 00042 public method getSelection {} 00043 public method getFilter {} 00044 public method getShowHidden {} 00045 public method getMode {} 00046 public method setFilter {filter}; ## \type TclString 00047 public method setShowHidden {showHidden}; ## \type TclNumber 00048 public method setMode {mode}; ## \type TclString 00049 public method clearSelection {} 00050 public method select {fileNames}; ## \type TclList 00051 public method new {{dirName ""}}; ## \type TclString 00052 00053 constructor {args} {}; ## \type TclList 00054 destructor {} 00055 00056 private method _cmpFiles {fileObj1 fileObj2}; ## \type VisFile, VisFile 00057 private method _draw {} 00058 private method _b1Click {} 00059 private method _ctrlB1Click {} 00060 private method _shiftB1Click {} 00061 private method _doubleB1Click {} 00062 private method _select {fileObjs}; ## \type TclList 00063 private method _unselect {fileObjs}; ## \type TclList 00064 private method _entryOkCommand {} 00065 private method _entryAbortCommand {} 00066 }; 00067 00068 ## ---------------------------------------------------------------------------- 00069 ## constructor 00070 ## ---------------------------------------------------------------------------- 00071 body VisDirectory::constructor {args} { 00072 00073 itk_component add renameEntry { 00074 entry $itk_interior.renameEntry \ 00075 -borderwidth 2 00076 } {} 00077 00078 # binding 00079 ::bind $itk_component(canvas) <Configure> [code $this _draw] 00080 ::bind $itk_component(renameEntry) <Return> [code $this _entryOkCommand] 00081 ::bind $itk_component(renameEntry) <Escape> [code $this _entryAbortCommand] 00082 00083 # canvas bindings 00084 bind all <ButtonPress-1> [code $this _b1Click] 00085 bind all <ButtonPress-2> [code $this _ctrlB1Click] 00086 bind all <ButtonPress-3> [code $this _shiftB1Click] 00087 bind all <Control-ButtonPress-1> [code $this _ctrlB1Click] 00088 bind all <Shift-ButtonPress-1> [code $this _shiftB1Click] 00089 bind all <Double-Button-1> [code $this _doubleB1Click] 00090 00091 00092 eval itk_initialize $args 00093 } 00094 00095 ## ---------------------------------------------------------------------------- 00096 ## destructor 00097 ## ---------------------------------------------------------------------------- 00098 body VisDirectory::destructor {} { 00099 hide 00100 } 00101 00102 ## ---------------------------------------------------------------------------- 00103 ## hide 00104 ## ---------------------------------------------------------------------------- 00105 body VisDirectory::hide {} { 00106 foreach obj $_fileObjects { 00107 itcl::delete object $obj 00108 } 00109 set _fileObjects "" 00110 set _selectedFiles "" 00111 set _selectionAnchor "" 00112 set _maxWidth 70 00113 set _maxHeight 0 00114 } 00115 00116 ## ---------------------------------------------------------------------------- 00117 ## show 00118 ## ---------------------------------------------------------------------------- 00119 body VisDirectory::show {dirName} { 00120 00121 # clear the previous view 00122 hide 00123 00124 # change the current directory to be shown 00125 cd $dirName 00126 set dirName [pwd] 00127 00128 # get all files in the actual directory 00129 set _fileObjects "" 00130 foreach file [eval glob -nocomplain .* *] { 00131 if {[info exists allFiles($file)]} { 00132 continue 00133 } 00134 00135 if {$dirName == "/" && ( $file == "." || $file == ".." )} { 00136 continue 00137 } 00138 00139 if {!$_showHidden && \ 00140 $file != "." && $file != ".." && \ 00141 [string index $file 0] == "."} { 00142 continue 00143 } 00144 00145 if {[file isdirectory $file]} { 00146 set icon [YadaImages::get defaultFolder] 00147 set type "directory" 00148 } else { 00149 if {$_fileMode == "dir"} { 00150 continue 00151 } 00152 00153 set doesMatch 0 00154 foreach pattern [split $_filter] { 00155 if {[string match $pattern $file]} { 00156 set doesMatch 1 00157 break 00158 } 00159 } 00160 if {!$doesMatch} { 00161 continue 00162 } 00163 00164 set icon [YadaImages::get textFile] 00165 set type "file" 00166 } 00167 00168 set fileObj [VisFile #auto $this \ 00169 -name $file \ 00170 -icon $icon \ 00171 -type $type] 00172 00173 lappend _fileObjects [namespace which $fileObj] 00174 set allFiles($file) 1 00175 00176 # keep track of the maximum width and height of VisFiles 00177 set width [$fileObj getWidth] 00178 if {$width > $_maxWidth} { 00179 set _maxWidth $width 00180 } 00181 set height [$fileObj getHeight] 00182 if {$height > $_maxHeight} { 00183 set _maxHeight $height 00184 } 00185 } 00186 00187 set _fileObjects [lsort -command [code $this _cmpFiles] $_fileObjects] 00188 set _selectionAnchor [lindex $_fileObjects 0] 00189 _draw 00190 00191 # call the chdir handle 00192 $chdircommand 00193 } 00194 00195 ## ---------------------------------------------------------------------------- 00196 ## _cmpFiles 00197 ## ---------------------------------------------------------------------------- 00198 body VisDirectory::_cmpFiles {fileObj1 fileObj2} { 00199 set file1 [$fileObj1 cget -name] 00200 set file2 [$fileObj2 cget -name] 00201 00202 if {$file1 == "."} { 00203 return -1 00204 } 00205 if {$file2 == "."} { 00206 return 1 00207 } 00208 if {$file1 == ".."} { 00209 return -1 00210 } 00211 if {$file2 == ".."} { 00212 return 1 00213 } 00214 00215 if {[file isdirectory $file1]} { 00216 if {[file isdirectory $file2]} { 00217 return [string compare $file1 $file2] 00218 } else { 00219 return -1 00220 } 00221 } 00222 00223 if {[file isdirectory $file2]} { 00224 return 1 00225 } else { 00226 return [string compare $file1 $file2] 00227 } 00228 } 00229 00230 ## ---------------------------------------------------------------------------- 00231 ## _draw 00232 ## ---------------------------------------------------------------------------- 00233 body VisDirectory::_draw {} { 00234 00235 set canvas $itk_component(canvas) 00236 set canvasHeight [expr [winfo height $canvas] - $_maxHeight] 00237 if {$canvasHeight < 0} { 00238 return 00239 } 00240 00241 set padding [expr [$canvas cget -highlightthickness] + [$canvas cget -bd]] 00242 if {$padding < 2} { 00243 set padding 2 00244 } 00245 set x $padding 00246 set y $padding 00247 set dx [expr $_maxWidth + $padding] 00248 set dy [expr $_maxHeight + $padding] 00249 00250 set canvasHeight [expr $canvasHeight - 2 * $padding] 00251 00252 foreach fileObj $_fileObjects { 00253 00254 $fileObj setCoords $x $y 00255 $fileObj show 00256 00257 set y [expr $y + $dy] 00258 if {$y > $canvasHeight} { 00259 set y $padding 00260 set x [expr $x + $dx] 00261 } 00262 } 00263 00264 # adjust the view 00265 configure -scrollregion [bbox all] 00266 xview moveto 0 00267 } 00268 00269 ## ---------------------------------------------------------------------------- 00270 ## _shiftB1Click 00271 ## ---------------------------------------------------------------------------- 00272 body VisDirectory::_shiftB1Click {} { 00273 if {$_browseMode == "single"} { 00274 return [_b1Click] 00275 } 00276 00277 if {$_selectionAnchor == ""} { 00278 _ctrlB1Click 00279 return 00280 } 00281 00282 set oldAnchor $_selectionAnchor 00283 clearSelection 00284 set _selectionAnchor $oldAnchor 00285 set id [find withtag current] 00286 set tags [itemcget $id -tags] 00287 set currentFileObj [lindex $tags 0] 00288 set fromIndex [lsearch $_fileObjects $_selectionAnchor] 00289 set toIndex [lsearch $_fileObjects $currentFileObj] 00290 00291 if {$fromIndex > $toIndex} { 00292 set tmp $toIndex 00293 set toIndex $fromIndex 00294 set fromIndex $tmp 00295 } 00296 00297 set selectedRange [lrange $_fileObjects $fromIndex $toIndex] 00298 00299 _select $selectedRange 00300 } 00301 00302 ## ---------------------------------------------------------------------------- 00303 ## _ctrlB1Click 00304 ## ---------------------------------------------------------------------------- 00305 body VisDirectory::_ctrlB1Click {} { 00306 if {$_browseMode == "single"} { 00307 return [_b1Click] 00308 } 00309 00310 set id [find withtag current] 00311 set tags [itemcget $id -tags] 00312 set fileObj [lindex $tags 0] 00313 00314 if {[$fileObj getSelection] == 0} { 00315 _select $fileObj 00316 set _selectionAnchor $fileObj 00317 } else { 00318 _unselect $fileObj 00319 } 00320 00321 } 00322 00323 ## ---------------------------------------------------------------------------- 00324 ## _b1Click 00325 ## ---------------------------------------------------------------------------- 00326 body VisDirectory::_b1Click {} { 00327 set id [find withtag current] 00328 set tags [itemcget $id -tags] 00329 set fileObj [lindex $tags 0] 00330 00331 set wasSelected [$fileObj getSelection] 00332 clearSelection 00333 if {$wasSelected} { 00334 _unselect $fileObj 00335 } else { 00336 _select $fileObj 00337 set _selectionAnchor $fileObj 00338 } 00339 } 00340 00341 ## ---------------------------------------------------------------------------- 00342 ## _doubleB1CLick 00343 ## ---------------------------------------------------------------------------- 00344 body VisDirectory::_doubleB1Click {} { 00345 set id [find withtag current] 00346 set tags [itemcget $id -tags] 00347 set fileObj [lindex $tags 0] 00348 set fileName [$fileObj cget -name] 00349 clearSelection 00350 00351 # change directory 00352 if {[$fileObj cget -type] == "directory"} { 00353 show $fileName 00354 } else { 00355 # select file 00356 _select $fileObj 00357 set _selectionAnchor $fileObj 00358 $finishcommand 00359 } 00360 } 00361 00362 ## ---------------------------------------------------------------------------- 00363 ## getMaxFileWidth 00364 ## ---------------------------------------------------------------------------- 00365 body VisDirectory::getMaxFileWidth {} { 00366 return $_maxWidth 00367 } 00368 00369 ## ---------------------------------------------------------------------------- 00370 ## getMaxFileHeight 00371 ## ---------------------------------------------------------------------------- 00372 body VisDirectory::getMaxFileHeight {} { 00373 return $_maxHeight 00374 } 00375 00376 ## ---------------------------------------------------------------------------- 00377 ## clearSelection 00378 ## ---------------------------------------------------------------------------- 00379 body VisDirectory::clearSelection {} { 00380 _unselect $_fileObjects 00381 } 00382 00383 ## ---------------------------------------------------------------------------- 00384 ## getSelection 00385 ## ---------------------------------------------------------------------------- 00386 body VisDirectory::getSelection {} { 00387 set selection "" 00388 foreach fileObj $_selectedFiles { 00389 lappend selection [$fileObj cget -name] 00390 } 00391 00392 return $selection 00393 } 00394 00395 ## ---------------------------------------------------------------------------- 00396 ## setFilter 00397 ## ---------------------------------------------------------------------------- 00398 body VisDirectory::setFilter {filter} { 00399 set _filter $filter 00400 clearSelection 00401 } 00402 00403 ## ---------------------------------------------------------------------------- 00404 ## getFilter 00405 ## ---------------------------------------------------------------------------- 00406 body VisDirectory::getFilter {} { 00407 return $_filter 00408 } 00409 00410 ## ---------------------------------------------------------------------------- 00411 ## setShowHidden 00412 ## ---------------------------------------------------------------------------- 00413 body VisDirectory::setShowHidden {showHidden} { 00414 set _showHidden $showHidden 00415 clearSelection 00416 } 00417 00418 ## ---------------------------------------------------------------------------- 00419 ## getShowHidden 00420 ## ---------------------------------------------------------------------------- 00421 body VisDirectory::getShowHidden {} { 00422 return $_showHidden 00423 } 00424 00425 ## ---------------------------------------------------------------------------- 00426 ## _select 00427 ## ---------------------------------------------------------------------------- 00428 body VisDirectory::_select {fileObjs} { 00429 foreach fileObj $fileObjs { 00430 $fileObj setSelection 1 00431 00432 if {($_fileMode == "file" && [$fileObj cget -type] == "directory") || 00433 ($_fileMode == "dir" && [$fileObj cget -type] == "file")} { 00434 continue 00435 } 00436 00437 if {[lsearch $_selectedFiles $fileObj] < 0} { 00438 lappend _selectedFiles $fileObj 00439 } 00440 } 00441 00442 $selectioncommand 00443 } 00444 00445 ## ---------------------------------------------------------------------------- 00446 ## _unselect 00447 ## ---------------------------------------------------------------------------- 00448 body VisDirectory::_unselect {fileObjs} { 00449 foreach fileObj $fileObjs { 00450 $fileObj setSelection 0 00451 set index [lsearch $_selectedFiles $fileObj] 00452 00453 if {$index >= 0} { 00454 set _selectedFiles [lreplace $_selectedFiles $index $index] 00455 } 00456 } 00457 00458 if {$_selectedFiles != ""} { 00459 set _selectionAnchor [lindex $_selectedFiles end] 00460 } else { 00461 set _selectionAnchor "" 00462 } 00463 $selectioncommand 00464 } 00465 00466 ## ---------------------------------------------------------------------------- 00467 ## getMode 00468 ## ---------------------------------------------------------------------------- 00469 body VisDirectory::getMode {} { 00470 return $_mode 00471 } 00472 00473 ## ---------------------------------------------------------------------------- 00474 ## set the selection mode. 00475 ## In effect the variables _browseMode and _fileMode are set. 00476 ## \param mode possible values are 00477 ## - multi: lets you select multiple files and directories 00478 ## - single: lets you select one file or directory 00479 ## - multidir: lets you select multiple directories 00480 ## - multifile: lets you select multiple files 00481 ## - singledir: lets you select one directory 00482 ## - singlefile: lets you select one file 00483 ## ---------------------------------------------------------------------------- 00484 body VisDirectory::setMode {mode} { 00485 00486 switch $mode { 00487 "multi" { 00488 set _browseMode "multi" 00489 set _fileMode "both" 00490 } 00491 "single" { 00492 set _browseMode "single" 00493 set _fileMode "both" 00494 } 00495 "multidir" { 00496 set _browseMode "multi" 00497 set _fileMode "dir" 00498 } 00499 "multifile" { 00500 set _browseMode "multi" 00501 set _fileMode "file" 00502 } 00503 "singledir" { 00504 set _browseMode "single" 00505 set _fileMode "dir" 00506 } 00507 "singlefile" { 00508 set _browseMode "single" 00509 set _fileMode "file" 00510 } 00511 default { 00512 error "ERROR: unknown mode `$mode'" 00513 } 00514 } 00515 } 00516 00517 ## ---------------------------------------------------------------------------- 00518 ## select 00519 ## ---------------------------------------------------------------------------- 00520 body VisDirectory::select {fileNames} { 00521 clearSelection 00522 00523 set toBeSelectedObjects "" 00524 foreach fileObj $_fileObjects { 00525 set fileName [file join [pwd] [$fileObj cget -name]] 00526 if {[lsearch $fileNames $fileName] >= 0} { 00527 lappend toBeSelectedObjects $fileObj 00528 } 00529 } 00530 00531 _select $toBeSelectedObjects 00532 set _selectionAnchor [lindex $_selectedFiles end] 00533 } 00534 00535 ## ---------------------------------------------------------------------------- 00536 ## new 00537 ## ---------------------------------------------------------------------------- 00538 body VisDirectory::new {{dirName ""}} { 00539 if {$dirName == ""} { 00540 00541 # get the next file position 00542 set lastFileObj [lindex $_fileObjects end] 00543 ::scan [$lastFileObj getCoords] "%f %d" x y 00544 set canvas $itk_component(canvas) 00545 set padding [expr [$canvas cget -highlightthickness] + [$canvas cget -bd]] 00546 if {$padding < 2} { 00547 set padding 2 00548 } 00549 set dx [expr $_maxWidth + $padding] 00550 set dy [expr $_maxHeight + $padding] 00551 set canvasHeight [expr [winfo height $canvas] - $_maxHeight - 2 * $padding] 00552 set y [expr $y + $dy] 00553 if {$y > $canvasHeight} { 00554 set y $padding 00555 set x [expr $x + $dx] 00556 } 00557 00558 set _doneFlag 0 00559 $itk_component(renameEntry) delete 0 end 00560 $itk_component(renameEntry) insert 0 "NewFolder" 00561 set entryTag [\ 00562 create window $x $y \ 00563 -anchor nw \ 00564 -width $_maxWidth \ 00565 -window $itk_component(renameEntry)] 00566 ::focus $itk_component(renameEntry) 00567 00568 vwait [scope _doneFlag] 00569 delete $entryTag 00570 set dirName [$itk_component(renameEntry) get] 00571 00572 if {$_doneFlag == 2 || $dirName =="" } { 00573 return 00574 } else { 00575 set _doneFlag 0 00576 } 00577 } else { 00578 set baseDir [file dirname $dirName] 00579 show $baseDir 00580 } 00581 00582 file mkdir $dirName 00583 show [pwd] 00584 } 00585 00586 ## ---------------------------------------------------------------------------- 00587 ## _entryOkCommand 00588 ## ---------------------------------------------------------------------------- 00589 body VisDirectory::_entryOkCommand {} { 00590 set _doneFlag 1 00591 } 00592 00593 ## ---------------------------------------------------------------------------- 00594 ## _entryAbortCommand 00595 ## ---------------------------------------------------------------------------- 00596 body VisDirectory::_entryAbortCommand {} { 00597 set _doneFlag 2 00598 }