1#
2# This file is part of:
3#
4#  gpsman --- GPS Manager: a manager for GPS receiver data
5#
6# Copyright (c) 1998-2013 Miguel Filgueiras migfilg@t-online.de
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 3 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.
20#
21#  File: lists.tcl
22#  Last change:  6 October 2013
23#
24
25proc ChangeOnStateList {wh st} {
26    # change state of items list when list becomes empty/non-empty
27    #  $wh in $TYPES or LAP
28    #  $st in {normal, disabled}
29    global LsW RcW RcMenu GPSState WConf RECTYPES
30
31    # entries in the type list menu and in the type sub-menu of Data menu
32    switch $wh {
33	WP {
34	    set es "1 2 5 6 7" ; set aes "1 2 4 5 6"
35	}
36	GR {
37	    set es "1 2 4 5 6 7 8 9" ; set aes "1 2 3 4 5 6 7 8"
38	}
39	LAP {
40	    set es "0 2" ; set aes "0 2"
41	}
42	default {
43	    set es "1 2 5 6" ; set aes "1 2 4 5"
44	}
45    }
46    if { [set ix [lsearch -exact $RECTYPES $wh]] != -1 } {
47	# reconfigure receiver window/menu
48	if { $wh == "GR" } {
49	    set bs "frget.frget2.getGR frput.putGR"
50	    $RcMenu.gm entryconfigure $WConf(rec,getmn,GR) -state $st
51	    $RcMenu.ptm entryconfigure $WConf(rec,putmn,GR) -state $st
52	} elseif { $wh != "IC" && $wh != "LAP" } {
53	    set bs "frput.put$wh"
54	    $RcMenu.ptm entryconfigure $WConf(rec,putmn,$wh) -state $st
55	} else { set bs "" }
56	if { $st == "normal" && $GPSState == "online" } {
57	    set sg normal
58	} else { set sg disabled }
59	foreach b $bs {
60	    $RcW.$b configure -state $sg
61	}
62    }
63    foreach e $es {
64	$LsW.frl$wh.frb.file.m entryconfigure $e -state $st
65    }
66    if { [set p $WConf(additemstate)] != "" } {
67	foreach e $aes {
68	    ${p}$wh entryconfigure $e -state $st
69	}
70    }
71    return
72}
73
74proc ClearList {wh} {
75    # forget all items in a list; $wh in $TYPES
76    global ListInds List EdWindow GMEd MESS TXT
77
78    if { $ListInds($wh) == "" || \
79	    ! [GMConfirm [format $MESS(forgetall) $TXT(name$wh)]] } { return }
80    set ixs $ListInds($wh)
81    if { [winfo exists $EdWindow($wh)] } {
82	GMMessage [format $MESS(cantfgted) $TXT(name$wh)]
83	set ixs [Delete $ixs $GMEd($wh,Index)]
84    }
85    # ForgetSeveral calls procs that update $ListInds($wh)
86    ForgetSeveral $wh $ixs
87    return
88}
89
90proc Count {wh} {
91    # count items in list; $wh in $TYPES
92    global Number MESS TXT
93
94    GMMessage [format $MESS(counted) $Number($wh) $TXT(name$wh)]
95    return
96}
97
98proc OpenListItem {wh} {
99    # edit or display selected item in a list; $wh in $TYPES
100    global LsW ListInds
101
102    set s [$LsW.frl$wh.frl.box curselection]
103    if { $s != "" } {
104	OpenItem $wh [lindex $ListInds($wh) $s]
105    }
106    return
107}
108
109proc ToggleDisplayItem {wh sel} {
110    # un-/display on map selected item in a list
111    #  $wh in $TYPES or LAP; $sel is selection index in list
112    global ListInds EdWindow GMEd ${wh}Displ Number
113
114    if { $wh == "LAP" } { return }
115    if { $Number($wh)>0 && $sel != "" } {
116	set index [lindex $ListInds($wh) $sel]
117	set w $EdWindow($wh)
118	if { [winfo exists $w] && $GMEd($wh,Index) == $index } {
119	    Raise $w ; bell
120	    return
121	}
122	if { [set [set wh]Displ($index)] } {
123	    UnMap $wh $index
124	} else { PutMap $wh $index }
125    }
126    return
127}
128
129proc ToggleDisplayNamed {wh name} {
130    # un-/display on map item with given name
131    #  $wh in $TYPES or LAP
132    global EdWindow GMEd ${wh}Displ
133
134    if { $wh == "LAP" } { return }
135    if { [set index [IndexNamed $wh $name]] == -1 } { return }
136    set w $EdWindow($wh)
137    if { [winfo exists $w] && $GMEd($wh,Index) == $index } {
138	Raise $w ; bell
139    } elseif { [set [set wh]Displ($index)] } {
140	UnMap $wh $index
141    } else { PutMap $wh $index }
142    return
143}
144
145proc ListAdd {wh index} {
146    # add new item with given index to non-empty list; $wh in $TYPES or LAP
147    global LsW ListInds Storage CMDLINE LAPStart
148
149    if { $CMDLINE } { return }
150
151    set ids [lindex $Storage($wh) 0]
152    global $ids
153    set name [set [set ids]($index)]
154    if { $ListInds($wh) == "" } {
155	set ListInds($wh) $index
156	$LsW.frl$wh.frl.box insert end $name
157	ChangeOnStateList $wh normal
158    } elseif { $wh != "LAP" } {
159	set a 0 ; set b [expr [$LsW.frl$wh.frl.box size]-1]
160	while 1 {
161	    set i [expr int(floor(($a+$b)/2))]
162	    if { [string compare $name [$LsW.frl$wh.frl.box get $i]] < 0 } {
163		set b $i
164	    } else { set a $i }
165	    if { $b == $a } {
166                if { [string compare $name \
167			[$LsW.frl$wh.frl.box get $a]] > 0 } {
168		    incr a
169		}
170		$LsW.frl$wh.frl.box insert $a $name
171		set ListInds($wh) [linsert $ListInds($wh) $a $index]
172		break
173            }
174	    if { $b == $a+1 } {
175		if { [string compare $name \
176			[$LsW.frl$wh.frl.box get $a]] > 0 } {
177		    incr a
178		    if { [string compare $name \
179			    [$LsW.frl$wh.frl.box get $a]] > 0 } {
180			incr a
181		    }
182		}
183		$LsW.frl$wh.frl.box insert $a $name
184		set ListInds($wh) [linsert $ListInds($wh) $a $index]
185		break
186	    }
187	}
188    } else {
189	# LAP: order by start date
190	set secs [lindex $LAPStart($index) 1]
191	set a 0 ; set nf 1
192	foreach ix $ListInds(LAP) {
193	    if { [lindex $LAPStart($ix) 1] <= $secs } {
194		set nf 0 ; break
195	    }
196	    incr a
197	}
198	if { $nf } { set a end }
199	$LsW.frl$wh.frl.box insert $a $name
200	set ListInds($wh) [linsert $ListInds($wh) $a $index]
201    }
202    return
203}
204
205proc ListDelete {wh index} {
206    # delete item with given index from list; $wh in $TYPES or LAP
207    global LsW ListInds
208
209    set n [lsearch -exact $ListInds($wh) $index ]
210    $LsW.frl$wh.frl.box delete $n
211    set ListInds($wh) [lreplace $ListInds($wh) $n $n]
212    if { [$LsW.frl$wh.frl.box size] == 0 } {
213	ChangeOnStateList $wh disabled
214    }
215    return
216}
217
218proc ListDeleteSeveral {wh ixs} {
219    # delete items with given indices from list; $wh in $TYPES or LAP
220    #  $ixs has the same order of $ListInds($wh) although with some
221    #    elements missing
222    global LsW ListInds
223
224    if { $ixs == "" } { return }
225    set exs $ListInds($wh) ; set ks ""
226    set bx $LsW.frl$wh.frl.box ; set ib 0
227    while { $ixs != "" } {
228	set c 0
229	foreach ex $exs ix $ixs {
230	    if { $ex == $ix } {
231		$bx delete $ib ; incr c
232	    } else {
233		lappend ks $ex ; incr ib
234		break
235	    }
236	}
237	set exs [lrange $exs [expr $c+1] end]
238	set ixs [lrange $ixs $c end]
239    }
240    set ListInds($wh) [concat $ks $exs]
241    if { $ib == 0 } {
242	ChangeOnStateList $wh disabled
243    }
244    return
245}
246
247proc ListDeleteAll {wh} {
248    # delete all items from list; $wh in $TYPES or LAP
249    global LsW ListInds
250
251    $LsW.frl$wh.frl.box delete 0 end
252    set ListInds($wh) ""
253    ChangeOnStateList $wh disabled
254    return
255}
256
257proc ChooseItems {wh args} {
258    # create modal dialog for selecting from list of items
259    #  $wh in $TYPES or LAP
260    #  $args is empty or a list whose head is in {single, many, many_0}
261    #    for a single element, at least one element, and zero or more
262    #    elements, and whose tail is a pair that is passed on to
263    #    GMChooseFrom and describes parameters
264    # return indices of items selected or "" if cancelled
265    global LISTWIDTH Storage ListInds TXT
266
267    set ids [lindex $Storage($wh) 0]
268    global $ids
269    set ns ""
270    foreach i $ListInds($wh) { lappend ns [set [set ids]($i)] }
271    if { $args != "" } {
272	return [GMChooseFrom [lindex $args 0] \
273		             [list $TXT(select) $TXT(name$wh)] \
274		             $LISTWIDTH $ns $ListInds($wh) \
275			     [lindex $args 1] [lindex $args 2]]
276    }
277    return [GMChooseFrom many [list $TXT(select) $TXT(name$wh)] \
278		         $LISTWIDTH $ns $ListInds($wh)]
279}
280
281proc ChItemsCall {wh mode comm args} {
282    # select from list of items and call command
283    #  $wh in $TYPES or LAP
284    #  $mode in {single, many, many_0} as in proc ChooseItems
285    #  $comm is command name to call as
286    #     $comm ARG0 ... ARGn NAMES
287
288    if { [set ixs [ChooseItems $wh $mode]] == "" } { return }
289    set names [Apply $ixs NameOf $wh]
290    eval $comm $args $names
291    return
292}
293
294proc InputToGR {whs notwhs preproc proc postproc fmt} {
295    # input data according to contents of group(s)
296    # items of types in $whs (except those in $notwhs) will be read in
297    #  $preproc will be called immediately before input is really required
298    #     and should return 0 unless operation is to be cancelled;
299    #     arguments: GR and $fmt; proc Ignore can be used if nothing is to
300    #     be done
301    #  $proc is the input procedure, whose arguments will be:
302    #     type of item to input, list of indices and $fmt if not "receiver"
303    #  $postproc will be called after the last call to $proc; single
304    #     argument: GR; proc Ignore can be used if nothing is to be done
305    #  $fmt is a either a file format (as used in the FILEFORMAT array)
306    #     or "receiver"
307    global MESS TXT GCHow ListInds Storage FILEFORMAT
308
309    set gts "" ; set ts ""
310    foreach t $whs {
311	if { [lsearch -exact $notwhs $t] == -1 } {
312	    lappend gts $t ; lappend ts $TXT(name$t)
313	}
314    }
315    set vals [list $TXT(notinGR) $TXT(onlyinGR)]
316    if { $fmt != "receiver" && $FILEFORMAT($fmt,filetype) == "data" } {
317	set mode many
318    } else { set mode single }
319    while 1 {
320	set whs [GMChooseFrom many $MESS(readwhat) 6 $ts $gts \
321		     GCHow [list $vals]]
322	set compl [string compare $GCHow $TXT(onlyinGR)]
323	if { [set i [lsearch -exact $whs GR]] != -1 } {
324	    set whs [lreplace $whs $i $i]
325	    set rec 1
326	} else { set rec 0 }
327	if { $mode == "single" && [llength $whs] > 1 } {
328	    GMMessage $MESS(importonly1)
329	} else { break }
330    }
331    if { $whs == "" || [set ixs [ChooseItems GR]] == "" } { return }
332    if { [$preproc GR $fmt] } { return }
333    if { $mode != "single" } {
334	set ll ""
335	foreach wh $whs {
336	    if { [set l [GRsElements $ixs $rec $wh]] != "" } {
337		if { $compl } {
338		    set ids [lindex $Storage($wh) 0]
339		    global $ids
340		    set l [linsert [Complement [array names $ids] $l] 0 -1]
341		}
342		lappend ll $l
343	    }
344	}
345	if { $ll != "" } { $proc $whs $ll $fmt }
346    } else {
347	# single
348	if { [set l [GRsElements $ixs $rec $whs]] != "" } {
349	    if { $compl } {
350		set ids [lindex $Storage($whs) 0]
351		global $ids
352		set l [linsert [Complement [array names $ids] $l] 0 -1]
353	    }
354	    if { $fmt != "receiver" } {
355		$proc $whs [list $l] $fmt
356	    } else {
357		$proc $whs $l
358	    }
359	}
360    }
361    $postproc GR
362    return
363}
364