File: dfm-open_dir.tcl

package info (click to toggle)
dfm 0.99.3-1
  • links: PTS
  • area: main
  • in suites: potato
  • size: 2,052 kB
  • ctags: 661
  • sloc: ansic: 10,980; tcl: 289; sh: 282; makefile: 216
file content (285 lines) | stat: -rw-r--r-- 8,103 bytes parent folder | download | duplicates (4)
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
#! /bin/sh
# restart with wish \
exec wish "$0"
#
# Name : dfm-open_dir.tcl
# Zweck: Eingabedialog zum ffnen eines DFM-Verzeichnisfensters.
# Autor: Christian V. J. Brssow <cvjb@bigfoot.de>
# Stand: Mit 03 Feb 1999 19:05:50 MET
# Notiz: BETA; en_GB (Skript wurde mit TAB=3 geschrieben; VIM)

# BESCHREIBUNG
#
# Stellt einen Eingabedialog mit einer Eingabezeile fr Verzeichnispfade
# dar. Das in dieser Eingabezeile angegebene Verzeichnis kann durch
# Drcken der Enter-Taste mit dem DFM geffnet werden; Aufruf: dfm <verz>.
# Tritt beim Start des DFM ein Fehler auf, so wird dies gemeldet.
#
# Existiert das Verzeichnis nicht, so wird eine entsprechende Meldung
# ausgegeben. Der Benutzer kann seine Eingabe anschlieend korrigieren.
# DFM wird nicht gestartet.
#
# Ist die Eingabe nicht komplett oder ist sich der Anwender nicht sicher,
# ob das Verzeichnis existiert bzw. kennt nicht den kompletten Namen, so
# kann durch Drcken der Tabulator-Taste eine Dateinamenexpansion
# eingeleitet werden; hnlich wie z.B. bei der Bash.
# Schlgt die Expansion fehl, so wird dies angezeigt.
# Ist die Expansion nicht eindeutig, so wird dies ebenfalls angezeigt,
# auerdem werden die mglichen Lsungen ausgegeben.
#
# Durch Drcken der Escape-Taste wird das Programm abgebrochen. DFM wird
# nicht gestartet.
#
# Durch Drcken der F1-Taste erhlt der Anwender eine kurze Angabe der
# Tastenbelegung. DFM wird nicht gestartet.


# VORGABEN

# Name des DFM-Programms. Ist DFM nicht im Suchpfad enthalten, so
# kann hier der komplette Pfad angegeben werden.
set DFM dfm

# Vorgabe im Eingabefeld ist das Home-Verzeichnis.
set dir $env(HOME)


# PROZEDUREN

# Ersatz fr tk_dialog.
# Setzt im Gegensatz zu tk_dialog die Schrift fr die Meldung
# nicht explizit.
# Steht hier, damit dieses Skript portabel bleibt. Bei dem Autor selbst
# wird diese Funktion durch sog. Autoloading aus einer Library geladen.
proc new_tk_dialog {w title text bitmap default args} {
	global tk_priv

	# Toplevelfenster erstellen.
	catch {destroy $w}

	toplevel $w -class Dialog
	wm title $w $title
	wm iconname $w Dialog

	# Fenster in zwei Hauptframes vertikal unterteilen.

	# Oberer Hauptframe.
	frame $w.top -relief raised -borderwidth 1
	pack $w.top -side top -fill both

		# Im oberen Frame wird die gewnschte Nachricht angezeigt.
		message $w.top.msg -aspect 320 -text $text
		pack $w.top.msg -side right -expand 1 -fill both -padx 5m -pady 5m

		# Ebenso wird optional, links neben der Nachricht eine Bitmap
		# ausgegebe.
		if {$bitmap != ""} {
			label $w.top.bitmap -bitmap $bitmap
			pack $w.top.bitmap -side left -padx 5m -pady 5m
		}
		
	# Unterer Hauptframe.
	frame $w.bot -relief raised -borderwidth 1
	pack $w.bot -side bottom -fill both

	# Im unteren Frame werden die angegebene Schalter positioniert.
	# Falls angegeben, wird der Vorgabeschalter gesondert hervorgehoben.
	set i 0
	foreach but $args {
		button $w.button$i -text $but -command "set tk_priv(button) $i"
		if {$i == $default} {
			# Vorgabeschalter.
			frame $w.bot.default -relief sunken -borderwidth 1
			raise $w.button$i $w.bot.default
			pack $w.bot.default -side left -expand 1 -padx 2m -pady 1m
			pack $w.button$i -in $w.bot.default -padx 1m -pady 1m -ipadx 0m -ipady 0m

			bind $w <Return> "$w.button$i flash ; set tk_priv(button) $i"
		} else {
			# Normaler Schalter.
			pack $w.button$i -in $w.bot -side left -expand 1 -padx 2m -pady 2m\
								-ipadx 0m -ipady 0m
		}
		incr i
	}

	# Das Fenster komplett vom Schirm entfernen, sein Layout aktualisieren.
	# Dann in der Mitte des Bildschirms positionieren; Angaben hierzu werden
	# aus seiner aktuellen Gre berechnet. Wenn alles klar ist, dann das
	# Fenster wieder auf dem Schirm darstellen.
	wm withdraw $w
	update idletasks
	set x [expr [winfo screenwidth $w]/2 - [winfo reqwidth $w]/2 \
								- [winfo vrootx [winfo parent $w]]]
	set y [expr [winfo screenheight $w]/2 - [winfo reqheight $w]/2 \
								- [winfo vrooty [winfo parent $w]]]
	wm geometry $w +$x+$y
	wm deiconify $w

	# Das Fenster erhlt den Focus und den Grab; Vorgngerfocus wird
	# aber gesichert.
	set old_focus [focus]
	grab $w
	focus $w

	# Jetzt solange warten, bis der Benutzer einen Knopf bettigt.
	# Dann das Fenster lschen und den alten Focus wieder herstellen.
	# Zuletzt wird die Kennung des gedrckten Knopfs als Funktionswert
	# zurckgeliefert.
	tkwait variable tk_priv(button)
	destroy $w
	focus $old_focus
	return $tk_priv(button)
}

# Prfen, ob $dir ein Verzeichnis ist/existiert.
# Wenn ja, dann wird 1 zurckgeliefert. Wenn nein, dann
# wird eine entsprechende Meldung angezeigt und 0
# zurckgeliefert.
proc is_dir dir {
	if [file isdirectory $dir] {
		return 1
	} else {
		new_tk_dialog .err_d {Fehler} \
			"$dir: no such directory. Typo?" \
			error 0 { Ok }
		return 0
	}
}

# Verzeichnis mit DFM ffnen.
proc start_dfm dir {
	global DFM

	if [is_dir $dir] {
		if ![catch { exec $DFM $dir & } ] {
			exit
		} else {
			new_tk_dialog .err_d {Error} \
				{Execution of DFM has failed} \
				error 0 { Ok }
			exit 1
		}
	}
}

# Expandiere die Zeichenkette zu einem passenden Verzeichnis,
# wenn es solch eines gibt. Schlgt der Expansionsversuch fehl,
# so wird $dir unverndert zurck gegeben.
proc expand_dir dir {
	# Expansion vornehmen.
	set expanded_dir [ glob -nocomplain $dir\* ]
	# War die Expansion erfolgreich?
	set l [ llength $expanded_dir ]
	if { $l == 0 } {
		# Nein: Expansion vollstndig fehlgeschlagen!
		set msg "There is no directory starting with $dir!"
		new_tk_dialog .msg_d {Completion not possible} $msg error 0 { Ok }
		return $dir
	} elseif { $l == 1 } {
		# Ja: expandierter Verzeichnispfad wird zurck geliefert.
		return $expanded_dir
	} else {
		# Nein: Ergebnis war nicht eindeutig, d.h. Angabe in $dir ist zu kurz.
		set msg "Possible completions:\n$expanded_dir"
		new_tk_dialog .msg_d {Insufficient statement} $msg warning 0 { Ok }
		return $dir
	}
}

# Kurze Hilfe ausgeben.
proc help {} {
	new_tk_dialog .help_d {Help} {Keys:
Enter	: open given directory with DFM
Esc	: cancel execution
Tab	: try completion of given dir.
F1	: show this short help
} question 0 { OK }
}


# WIDGETS DEFINIEREN

frame .plane -relief raised -borderwidth 1

# Bezeichner fr die erwartete Eingabe.
label .plane.label -text "DIR:"

# Eingabezeile.
entry .plane.entry -textvariable dir -width 32 -relief sunken -borderwidth 1


# EVENTS

# Globale Events

# Return-Taste => Eingabe bernehmen und damit den DFM starten.
# ESC-Taste => Eingabe verwerfen und Programm abbrechen.
bind all <Return> {start_dfm $dir}
bind all <Escape> {exit}
bind all <F1> {help}

# Lokale Events

# TAB-Taste in Eingabezeile => Suche nach passendem Verzeichnis.
# ACHTUNG: das Standard-Binding fr TAB wird auer Kraft gesetzt.
bind .plane.entry <Tab> {set dir [expand_dir $dir]
								.plane.entry icursor end
								break}


# FOCUS
		
# Den Focus bekommt die Eingabezeile.
focus .plane.entry


# SELEKTION

# Die Vorgabe in der Eingabezeile wird markiert.
# Erleichtert schnelles berschreiben der Vorgabe.
.plane.entry selection range 0 end


# WIDGETS DARSTELLEN

# Zuerst die Unterwidgets.
pack .plane.label -side left -fill x
pack .plane.entry -side left -fill x -expand 1

# Zuletzt das Hauptwidget, dadurch erscheinen das Widgetensemble
# quasi auf einen Schlag.
pack .plane -fill x


# APPLIKATIONSFENSTER

# Das Fenster ist ein sog; transientes Fenster.
# Diese Fenster ist sein eigener Master! Dies ist ein etwas
# unsauberer Trick, um ein transientes Fenster ohne "wirkliches"
# Masterfenster zu erzeugen.
wm transient . . 

# Fenster- und Icontitel.
wm title . "Open directory"
wm iconname . "open dir"

# Fixe Fenstergre.
wm geometry . {}
wm resizable . 0 0

# Fenster in der Bildschirmmitte positionieren.
# Zuerst mu die Fenstermitte bestimmt werden.
wm withdraw .
set x [expr [winfo screenwidth .]/2 - [winfo reqwidth .]/2 \
      - [winfo vrootx .]]
set y [expr [winfo screenheight .]/2 - [winfo reqheight .]/2 \
      - [winfo vrooty .]]
wm geometry . +$x+$y
wm deiconify .

# Explizit alles neu darstellen.
update idletasks


# vim: set tw=128 sw=3 ts=3 nocindent: