# Copyright (c) 1993 by Sanjay Ghemawat
##############################################################################
# DayView
#
# DESCRIPTION
# ===========
# A DayView shows the notices and appointments for one day.

# Global state for menus, etc.

set dv_state(clipboard) ""
set dv_state(views)     {}

# Autoload support
proc DayView {} {}

class DayView {} {
    global dv_state

    lappend dv_state(views) $self
    set dv_state($self,remind)    -1
    set dv_state($self,defremind) -1
    set dv_state($self,hilite)    ""

    set name .$self
    set slot(window) $name
    set slot(focus) ""
    set slot(focuswindow) ""

    # XXX Ignore any geometry default because toplevel does not understand ita
    toplevel $name -bd 0 -class Dayview -geometry ""

    focus_interest $name
    bind $name <Any-Enter> [list focus_restrict $name]

    $self build_menu
    $name.menu.custom.m configure -postcommand [list $self config_custom]
    $name.menu.edit.m   configure -postcommand [list $self config_edit]

    set slot(apptlist) [ApptList $name.al $self]
    set slot(notelist) [NoteList $name.nl $self]
    set slot(dateeditor) [DateEditor $name.de [date today] [list $self set_date]]

    frame $name.status -relief raised -bd 1
    label $name.cal -relief flat -text ""
    label $name.rep -relief flat -text ""
    pack append $name.status $name.cal {left}
    pack append $name.status $name.rep {right}

    pack append $name $name.menu {top fillx}
    pack append $name $name.status {bottom fillx}

    $self pack
    $self geometry

    wm title $name Calendar
    wm iconname $name ical
    wm protocol $name WM_DELETE_WINDOW [list $self close]

    # Set-up geometry
    set g [option get $name geometry Geometry]
    if {$g != ""} {
	wm geometry $name $g
    }

    $self set_date [date today]

    bind $name <Any-KeyPress> [list $self key %A]

    # Useful for updating status window.
    # Save is not useful because dayview never keeps unsaved changes.
    # Add/delete/include/exclude are not useful because we are only
    # interested in the currently selected item, and one of our
    # subwindows is going to tell us about it anyway.
    trigger on change	[list $self change]

    # Useful for reconfiguration
    trigger on include	[list $self included]

    # To advance the view at midnight
    trigger on midnight [list $self midnight]

    run-hook dayview-startup $self
}

method DayView window {} {
    return $slot(window)
}

method DayView dateeditor {} {
    return $slot(dateeditor)
}

method DayView cleanup {} {
    global dv_state

    set i [lsearch -exact $dv_state(views) $self]
    if {$i >= 0} {
	set dv_state(views) [lreplace $dv_state(views) $i $i]
    }

    if {[llength $dv_state(views)] == 0} {
	run-hook ical-exit
	destroy .
    } else {
	focus_disinterest $slot(window)
	focus_unrestrict $slot(window)

	unset dv_state($self,remind)
	unset dv_state($self,hilite)
	unset dv_state($self,overflow)
	unset dv_state($self,ampm)
	unset dv_state($self,mondayfirst)
	unset dv_state($self,defremind)

	trigger remove change [list $self change]
	trigger remove include [list $self included]
	trigger remove midnight [list $self midnight]

	class_kill $slot(apptlist)
	class_kill $slot(notelist)
	class_kill $slot(dateeditor)
	destroy $slot(window)
    }
}

method DayView set_date {date} {
    set slot(date) $date
    $slot(dateeditor) set_date $date
    $slot(apptlist) set_date $date
    $slot(notelist) set_date $date
}

# Called at midnight by a trigger.  Advance to today if appropriate.
method DayView midnight {} {
    # Only advance if at previous date
    set today [date today]
    if {$slot(date) == ($today-1)} {$self set_date $today}
}

method DayView focus {item itemwindow} {
    set slot(focus) $item
    set slot(focuswindow) $itemwindow

    global dv_state
    set dv_state($self,remind) [$item earlywarning]
    set dv_state($self,hilite) [$item hilite]

    global dv_state
    foreach entry $dv_state(item_entries) {
	$slot(window).menu.[lindex $entry 0].m entryconfig [lindex $entry 1]\
	    -state normal
    }

    if ![$item is appt] {
	$slot(window).menu.edit.m entryconfig {Change Alarms} -state disabled
    }

    $self update_status
}

method DayView unfocus {} {
    set slot(focus) ""
    set slot(focuswindow) ""

    global dv_state
    set dv_state($self,remind) -1
    set dv_state($self,hilite) ""

    global dv_state
    foreach entry $dv_state(item_entries) {
	$slot(window).menu.[lindex $entry 0].m entryconfig [lindex $entry 1]\
	    -state disabled
    }

    $self update_status
}

method DayView change {item} {
    if {$slot(focus) == $item} {
	global dv_state
	set dv_state($self,remind) [$item earlywarning]

	$self update_status
    }
}

method DayView included {cal} {
    if {$cal == [cal main]} {
	$self reconfig
    }
}

method DayView update_status {} {
    set item $slot(focus)
    if {$item == ""} {
	$slot(window).cal configure -text ""
	$slot(window).rep configure -text ""
    } else {
	set disp [file tail [$item calendar]]

	if {[$item hilite] == "holiday"} {
	    set disp [format {%s Holiday} $disp]
	}

	set owner [$item owner]
	if {$owner != ""} {
	    set disp [format {%s [%s]} $disp $owner]
	}

	$slot(window).cal configure -text $disp
	$slot(window).rep configure -text [$item type]
    }
}

method DayView key {{str ""}} {
    if {$str == "\003"} {
	# Control-c
	$self copy
	return
    }

    if {$str == "\026"} {
	# Control-v
	$self paste
	return
    }

    if {$str == "\030"} {
	# Control-x
	$self cut_or_hide
	return
    }

    # Pass event down to focus window if any
    if {$slot(focuswindow) != ""} {
	$slot(focuswindow) key $str
    }
}

method DayView save {} {
    trigger fire save
    foreach file [ical_filenames] {
	if ![cal dirty $file] {continue}

	if [cal stale $file] {
	    set query\
		[yes_no_cancel $slot(window)\
		 "$file has been modified since last read. Write anyway?"]
	    if {$query == "cancel"} {
		return 0
	    }
	    
	    if {$query == "no"} {
		continue
	    }

	    # If user said "yes", fall through and save.
	}
	
	if [catch {cal save $file} error] {
	    error_notify $slot(window) "$file\n\n$error"
	    return 0
	}
    }
    return 1
}

method DayView reread {} {
    trigger fire save

    # Cannot use [ical_filenames] because main calendar may change
    # in the middle of the iteration.

    set cleanup 0
    if [$self reread_calendar [cal main]] {set cleanup 1}
    cal forincludes file {
	if [$self reread_calendar $file] {set cleanup 1}
    }

    if $cleanup {alarmer cleanup}
}

# effects - Read calendar in "file" if it has changed since
#	    last read.  Return true iff calendar was read.
method DayView reread_calendar {file} {
    if ![cal stale $file] {return 0}

    if [cal dirty $file] {
	set query\
	    [yes_no_cancel $slot(window)\
	     "$file has been modified locally. Discard changes?"]
	if {$query == "cancel"} {
	    return 0
	}
	
	if {$query == "no"} {
	    return 0
	}
    }

    trigger fire exclude $file
    if [catch {cal reread $file} error] {
	trigger fire include $file
	error_notify $slot(window) "$file\n\n$error"
	return 0
    }
    trigger fire include $file

    return 1
}

method DayView exit {} {
    if ![$self save] return

    run-hook ical-exit
    destroy .
}

method DayView newview {} {
    DayView
}

method DayView close {} {
    run-hook dayview-close $self

    global dv_state
    if {[llength $dv_state(views)] <= 1} {
	# Last view about to be closed - try and save.
	if ![$self save] return
    }
    class_kill $self
}

method DayView cut_or_hide {} {
    set item [$self selection]
    if {$item == ""} {
	return
    }

    # If I own the item, or it is in the main calendar,
    # just delete it.  Else hide it from my view.

    if {[$item owned] || ([$item calendar] == [cal main])} {
	$self cut
    } else {
	$self hide
    }
}

method DayView cut {} {
    set item [$self mod_single_selection]
    if {$item == ""} {
	return
    }

    global dv_state
    if {$dv_state(clipboard) != ""} {$dv_state(clipboard) delete}
    set dv_state(clipboard) [$item clone]

    trigger fire delete $item
    cal remove $item
}

method DayView hide {} {
    set item [$self selection]
    if {$item == ""} {
	return
    }

    # Since the hide entry will go in the main calendar,
    # check for permission there.
    if [cal readonly] {
	error_notify $slot(window) "Permission denied"
	return
    }

    # Try to avoid checking permission in the item calendar
    # unless we have to split a repeating item.

    if [$item repeats] {
	if [cal readonly [$item calendar]] {
	    # Tell user that the item cannot be split.
	    # See if all entries should be hidden.
	    if {![yes_or_no $slot(window) {This item repeats and you are not allowed to split it.  Do you want to hide all occurrences of this item from your view?}]} {
		return
	    }
	} else {
	    # Query about split etc.
	    set item [$self mod_single_selection]
	    if {$item == ""} {
		return
	    }
	}
    }
		     
    global dv_state
    if {$dv_state(clipboard) != ""} {$dv_state(clipboard) delete}
    set dv_state(clipboard) [$item clone]

    trigger fire delete $item
    cal hide $item
}

method DayView copy {} {
    set item [$self selection]
    if {$item != ""} {
	global dv_state
	if {$dv_state(clipboard) != ""} {$dv_state(clipboard) delete}
	set dv_state(clipboard) [$item clone]
    }
}

method DayView paste {} {
    if [cal readonly] {
	error_notify $slot(window) "Permission denied"
	return
    }

    global dv_state
    if {$dv_state(clipboard) == ""} {
	error_notify $slot(window) "No item in clipboard"
	return
    }

    set item [$dv_state(clipboard) clone]
    $item date $slot(date)
    $item own
    cal add $item
    trigger fire add $item
}

method DayView insert {} {
    if {$slot(focuswindow) != ""} {
	# Try pasting selection
	$slot(focuswindow) key "\031"
    }
}

method DayView import {} {
    if [catch {set sel [selection get]}] {return}

    if ![cal readonly] {
	set item [item_parse $sel $slot(date)]
	cal add $item
	trigger fire add $item
	$self set_date [$item first]
    }
}

method DayView makeunique {} {
    set item [$self mod_selection]
    if {$item != ""} {
	if ![$item repeats] {
	    error_notify $slot(window) "Item does not repeat."
	    return
	}

	set clone [$item clone]
	$clone date $slot(date)
	$item deleteon $slot(date)

	cal add $clone [$item calendar]
	cal changed $item

	trigger fire change $item
	trigger fire add $clone
    }
}

method DayView moveitem {calendar} {
    if [cal readonly $calendar] {
	error_notify $slot(window) "$calendar: permission denied"
	return
    }

    set item [$self mod_single_selection]
    if {$item != ""} {
	set clone [$item clone]
	cal add $clone $calendar
	trigger fire add $clone

	trigger fire delete $item
	cal remove $item
    }
}

method DayView addinclude {} {
    if [cal readonly] {
	error_notify $slot(window) "[cal main]: permission denied"
	return
    }

    if [get_file_name $slot(window) "Include Calendar"\
	"Select calendar file to include." filename] {

	# Some sanity checking
	if [file exists $filename] {
	    if ![file isfile $filename] {
		error_notify $slot(window) "$filename: not a regular file"
		return
	    }

	    if ![file readable $filename] {
		error_notify $slot(window) "$filename: permission denied"
		return
	    }
	}

	if [catch {cal include $filename} error] {
	    error_notify $slot(window) $error
	    return
	}
	trigger fire include $filename
    }
}

method DayView removeinc {calendar} {
    if [cal readonly] {
	error_notify $slot(window) "[cal main]: permission denied"
	return
    }

    if [catch {set dirty [cal dirty $calendar]}] {
	# Unknown calendar - probably because a tear-off menu
	# allowed multiple invocations of removeinc.
	return
    }

    if $dirty {
	set save 1
	if [cal stale $calendar] {
	    # Conflict!
	    set query [yes_no_cancel $slot(window)\
		       "$calendar has been modified since last read. Save?"]
	    if ($query == "cancel") {
		return
	    }
	    if ($query == "no") {
		set save 0
	    }
	}

	if $save {
	    if [catch {cal save $calendar} error] {
		error_notify $slot(window) "$file\n\n$error"
		return
	    }
	}
    }

    # Remove it
    trigger fire exclude $calendar
    cal exclude $calendar
    alarmer cleanup
}

method DayView norepeat {} {
    set item [$self mod_selection]
    if {$item != ""} {
	$item date $slot(date)
	cal changed $item
	trigger fire change $item
    }
}

method DayView days {n} {
    set item [$self mod_selection]
    if {$item != ""} {
	$item dayrepeat $n $slot(date)
	cal changed $item
	trigger fire change $item
    }
}

method DayView months {n} {
    set item [$self mod_selection]
    if {$item != ""} {
	$item monthrepeat $n $slot(date)
	cal changed $item
	trigger fire change $item
    }
}

method DayView weekdays {} {
    set item [$self mod_selection]
    if {$item != ""} {
	if ![weekday_set $slot(window) result [date weekday $slot(date)]] {
	    return
	}

	if {[llength $result] < 1} {
	    error_notify $slot(window) "No weekday selected."
	    return
	}

	eval $item weekdays $result
	cal changed $item
	trigger fire change $item
    }
}

method DayView firstdate {} {
    set item [$self mod_selection]
    if {$item != ""} {
	$item start $slot(date)
	cal changed $item
	trigger fire change $item
    }
}

method DayView lastdate {} {
    set item [$self mod_selection]
    if {$item != ""} {
	$item finish $slot(date)
	cal changed $item
	trigger fire change $item
    }
}

method DayView alarms {} {
    set item [$self mod_selection]
    if {$item == ""} {return}

    if [catch {set alarms [$item alarms]}] {
	set alarms [cal option DefaultAlarms]
    }
    if ![alarm_set $slot(window) alarms $alarms] {return}

    # Make sure item still exists
    catch {
	$item alarms $alarms
	cal changed $item
	trigger fire change $item
    }
}

method DayView remind {n} {
    set item [$self mod_selection]
    if {$item != ""} {
	$item earlywarning $n
	cal changed $item
	trigger fire change $item
    }
}

method DayView hilite {mode} {
    set item [$self mod_single_selection]
    if {$item != ""} {
	$item hilite $mode
	cal changed $item
	trigger fire change $item
    }
}

method DayView print {} {
    if [catch {print_calendar $slot(window) $slot(date)} msg] {
	error_notify $slot(window) $msg
    }
}

method DayView viewitems {calendar} {
    set l [ItemListing]
    $l calendar $calendar
}

method DayView list {n} {
    set start $slot(date)
    if {$n == "week"} {
	set start [expr $slot(date)+1-[date weekday $slot(date)]]
	if [cal option MondayFirst] {
	    incr start
	    if {$start > $slot(date)} {
		set start [expr $start - 7]
	    }
	}
	set n 7
    }
    if {$n == "month"} {
	set start [expr $slot(date)+1-[date monthday $slot(date)]]
	set n [date monthsize $start]
    }
    if {$n == "year"} {
	set start [date make 1 1 [date year $slot(date)]]
	set n [expr [date make 1 1 [expr [date year $slot(date)]+1]] - $start]
    }

    set l [ItemListing]
    $l dayrange $start [expr $start+$n-1]
}

method DayView toggle_overflow {} {
    global dv_state
    if [cal readonly] {return}

    cal option AllowOverflow $dv_state($self,overflow)
}

method DayView toggle_ampm {} {
    global dv_state
    if [cal readonly] {return}

    cal option AmPm $dv_state($self,ampm)
    $self reconfig_all
}

method DayView toggle_monday {} {
    global dv_state
    if [cal readonly] {return}

    cal option MondayFirst $dv_state($self,mondayfirst)
    $self reconfig_all
}

method DayView timerange {} {
    if [cal readonly] {return}

    set start [cal option DayviewTimeStart]
    set finish [cal option DayviewTimeFinish]

    set msg {Use the two sliders to change the range of time displayed by default in a Calendar window.}

    if [get_time_range $slot(window) $msg start finish] {
	cal option DayviewTimeStart $start
	cal option DayviewTimeFinish $finish
	$self reconfig_all
    }
}

method DayView noticeheight {} {
    if [cal readonly] {return}

    set ht [cal option NoticeHeight]

    if [get_number $slot(window) {Notice Window Height} {In centimeters}\
	1 15 0 $ht ht] {
	cal option NoticeHeight $ht
	$self reconfig_all
    }
}

method DayView itemwidth {} {
    if [cal readonly] {return}

    set w [cal option ItemWidth]

    if [get_number $slot(window) {Item Width} {In centimeters}\
	5 15 0 $w w] {
	cal option ItemWidth $w
	$self reconfig_all
    }
}

method DayView defremind {n} {
    if [cal readonly] {return}

    cal option DefaultEarlyWarning $n
}

# effects - Edit default set of alarms for this user
method DayView defalarms {} {
    if [cal readonly] {return}

    set alarms [cal option DefaultAlarms]
    if ![alarm_set $slot(window) alarms $alarms] {return}

    cal option DefaultAlarms $alarms
    alarmer recompute
}

method DayView reconfig_all {} {
    global dv_state
    foreach v $dv_state(views) {
	$v reconfig
    }
}

method DayView reconfig {} {
    set name .$self
    $slot(apptlist) reconfig
    $slot(notelist) reconfig
    $slot(dateeditor) reconfig
    $self geometry
}

method DayView pack {} {
    set name .$self
    pack $name.menu	-side top -fill x
    pack $name.status	-side bottom -fill x
    pack $name.al	-side right -expand 1 -fill both
    pack $name.nl	-side bottom -expand 1 -fill both
    pack $name.de	-side top -fill x
}

method DayView geometry {} {
    set name .$self

    # Geometry management
    set width [winfo pixels $name "[cal option ItemWidth]c"]

    set start [cal option DayviewTimeStart]
    set finish [cal option DayviewTimeFinish]
    wm grid $name\
	1\
	[expr ($finish - $start) * 2]\
	$width\
	[pref itemLineHeight]
    wm minsize $name 1 10
    wm maxsize $name 1 48
}

method DayView build_menu {} {
    set m $slot(window).menu

    # Menu bar
    frame $m -relief raised -bd 1

    set menu_list ""

    global dayview_menus
    foreach menu $dayview_menus {
	set title [lindex $menu 0]
	set name [lindex $menu 1]
	set menu [lrange $menu 2 end]

	# Create menu
	lappend menu_list $m.$name
	menubutton $m.$name -bd 1 -text $title -menu $m.$name.m -padx 2m
	menu $m.$name.m -bd 1
	pack append $m $m.$name {left}

	# Fill menu
	foreach entry $menu {
	    if {[lindex $entry 0] == "-"} {
		$m.$name.m add separator
		continue
	    }

	    if {[lindex $entry 0] == ">"} {
		set x $m.$name.m.[lindex $entry 2]
		$m.$name.m add cascade\
		    -label [lindex $entry 1]\
		    -menu $x
		menu $x -postcommand [concat $self [lindex $entry 3] $x]
		continue
	    }

	    if {[lindex $entry 0] == "="} {
		$m.$name.m add radiobutton\
		    -label [lindex $entry 1]\
		    -variable dv_state($self,[lindex $entry 2])\
		    -value [lindex $entry 3]\
		    -command [concat $self [lindex $entry 4]]
		continue
	    }

	    if {[lindex $entry 0] == "x"} {
		$m.$name.m add checkbutton\
		    -label [lindex $entry 1]\
		    -command [list $self [lindex $entry 3]]\
		    -offvalue 0\
		    -onvalue 1\
		    -variable dv_state($self,[lindex $entry 2])
		continue
	    }

	    $m.$name.m add command\
		-label [lindex $entry 0]\
		-accelerator [lindex $entry 1]\
		-command [concat $self [lindex $entry 2]]
	}
    }

    eval tk_menuBar $m $menu_list

    global dv_state
    foreach entry $dv_state(item_entries) {
	$m.[lindex $entry 0].m entryconfig [lindex $entry 1] -state disabled
    }
}

# Description of Menu entries
#
#	Separator
#	{ - }
#
#	Command
#	{ <label> <accelerator> <command> }
#
#	Cascade
#	{ > <label> <pulldown-menu-id> <command> }
#
#	Radiobutton
#	{ = <label> <variable-id> <value> <command> }
#
#	Checkbutton
#	{ x <label> <variable-id> <command> }

set dayview_menus {
    { File file
	{ Save			{}	{save}		}
	{ Re-Read		{}	{reread}	}
	{ Print			{}	{print}		}
	{ -						}
	{ {Include Calendar}	{}	{addinclude}	}
	{ > {Remove Include} {remove} {fillinc other removeinc} }
	{ -						}
	{ {New Window}		{}	{newview}	}
	{ {Close Window}	{}	{close}		}
	{ -						}
	{ Exit			{}	{exit}		}
    }

    { Edit edit
	{ {Cut}			{^x}	{cut_or_hide}	}
	{ {Copy}		{^c}	{copy}		}
	{ {Paste}		{^v}	{paste}		}
	{ {Insert Selection}	{^y}	{insert}	}
	{ {Import Selection}	{}	{import}	}
	{ -						}
	{ {Make Unique}		{}	 {makeunique}	}
	{ {Change Alarms}	{}	 {alarms}	}
	{ > {List Item}		{early}	 {early remind remind}	}
	{ > {Highlight}		{hilite} {hilitemenu}	}
	{ -						}
	{ > {Move Item To}   {move}   {fillinc all moveitem} }
    }

    { Repeat rep
	{ {Don't Repeat}	{}	{norepeat}	}
	{ {Daily}		{}	{days 1}	}
	{ {Weekly}		{}	{days 7}	}
	{ {Monthly}		{}	{months 1}	}
	{ {Annual}		{}	{months 12}	}
	{ -						}
	{ {Days of the Week}	{}	{weekdays}	}
	{ -						}
	{ {Every Two Weeks}	{}	{days 14}	}
	{ {Every Three Weeks}	{}	{days 21}	}
	{ {Every Four Weeks}	{}	{days 28}	}
	{ -						}
	{ {Every Two Months}	{}	{months 2}	}
	{ {Every Three Months}	{}	{months 3}	}
	{ {Every Four Months}	{}	{months 4}	}
	{ {Every Six Months}	{}	{months 6}	}
	{ -						}
	{ {Make First Date}	{}	{firstdate}	}
	{ {Make Last Date}	{}	{lastdate}	}
    }

    { List list
	{ {One Day}		{}	{list 1}	}
	{ {Seven Days}		{}	{list 7}	}
	{ {Ten Days}		{}	{list 10}	}
	{ {Thirty Days}		{}	{list 30}	}
	{ {Week}		{}	{list week}	}
	{ {Month}		{}	{list month}	}
	{ {Year}		{}	{list year}	}
	{ -						}
	{ > {From Calendar} {items}  {fillinc all viewitems} }
    }

    { Options custom
	{ {Appointment Range}      {}		  {timerange}		}
	{ {Notice Window Height}   {}		  {noticeheight}	}
	{ {Item Width}		   {}		  {itemwidth}		}
	{ -								}
	{ x {Allow Text Overflow}  {overflow}	  {toggle_overflow}	}
	{ x {Display Am/Pm}	   {ampm}	  {toggle_ampm}		}
	{ x {Start Week on Monday} {mondayfirst}  {toggle_monday}	}
	{ -								}
	{ {Default Alarms}	 {}		  {defalarms}		}
	{ > {Default Listings}   {early}	  {early defremind defremind} }
    }
}

# List of <menu,entry> pairs for menu entries that should only be
# enabled when an item is selected.
set dv_state(item_entries) {
    { edit	{Cut}			}
    { edit	{Copy}			}
    { edit	{Insert Selection}	}
    { edit	{Make Unique}		}
    { edit	{Move Item To}		}
    { edit	{Change Alarms}		}
    { edit	{List Item}		}
    { edit	{Highlight}		}
    { rep	{Don't Repeat}		}
    { rep	{Daily}			}
    { rep	{Weekly}		}
    { rep	{Monthly}		}
    { rep	{Annual}		}
    { rep	{Days of the Week}	}
    { rep	{Every Two Weeks}	}
    { rep	{Every Three Weeks}	}
    { rep	{Every Four Weeks}	}
    { rep	{Every Two Months}	}
    { rep	{Every Three Months}	}
    { rep	{Every Four Months}	}
    { rep	{Every Six Months}	}
    { rep	{Make First Date}	}
    { rep	{Make Last Date}	}
}

# effects - Fill $menu with list of include file names.  If $type == all,
#	    also put main calendar into $menu.  Set-up the $menu entries
#	    so that they all execute "$self $cmd <include-file-name>".
method DayView fillinc {type cmd menu} {
    $menu delete 0 last
    if {$type == "all"} {
	$menu add command -label "Main Calendar"\
	    -command [concat $self $cmd [cal main]]
	$menu add separator
    }

    cal forincludes file {
	$menu add command -label [file tail $file]\
	    -command [concat $self $cmd $file]
    }
}

#############################################################################
# Helper methods

# effects - Check that item is currently selected and returns it.
#	    Warns user and returns "" if not selected.
method DayView selection {} {
    if {$slot(focus) == ""} {
	error_notify $slot(window) "No item selected."
	return ""
    }

    # Save pending edits
    trigger fire save

    return $slot(focus)
}

# effects - Check that item is currently selected and can be modified.
#	    Warns user and returns "" if not selected or immutable.
method DayView mod_selection {} {
    set focus [$self selection]
    if {$focus == ""} {return ""}

    if [cal readonly [$focus calendar]] {
	error_notify $slot(window) "[$focus calendar]: permission denied"
	return ""
    }
    return $focus
}

# effects - Check that item is currently selected, can be modified,
#	    and also performs a repeat_check.
#	    Warns user and returns "" if not selected or immutable.
#	    Returns "" if repeat_check fails.
method DayView mod_single_selection {} {
    set focus [$self mod_selection]
    if {$focus == ""} {return ""}

    # Repeat-modify-check
    if {[repeat_check $slot(window) $focus $slot(date)] == "cancel"} {
	return ""
    }
    return $focus
}

# effects - Fill menu for early warning options
method DayView early {cmd var menu} {
    # No need to re-execute the -postcommand
    $menu configure -postcommand ""

    set entries {
	{ {On Occurrence}	0 }
	{ {A Day Early}		1 }
	{ {Two Days Early}	2 }
	{ {Five Days Early}	5 }
	{ {Ten Days Early}	10 }
	{ {Fifteen Days Early}	15 }
    }

    foreach e $entries {
	$menu add radiobutton\
	    -label [lindex $e 0]\
	    -variable dv_state($self,$var)\
	    -value [lindex $e 1]\
	    -command [list $self $cmd [lindex $e 1]]
    }
}

# effects - Fill hilite menu
method DayView hilitemenu {menu} {
    # No need to re-execute the -postcommand
    $menu configure -postcommand ""

    set entries {
	{ {Always}		{always}	}
	{ {Until Occurrence}	{expire}	}
	{ {Never}		{never}		}
	{ {As Holiday}		{holiday}	}
    }

    foreach e $entries {
	$menu add radiobutton\
	    -label [lindex $e 0]\
	    -variable dv_state($self,hilite)\
	    -value [lindex $e 1]\
	    -command [list $self hilite [lindex $e 1]]
    }
}

# effects - Configure the customization menu
method DayView config_custom {} {
    global dv_state

    set state normal
    if [cal readonly] {set state disabled}

    set menu $slot(window).menu.custom.m
    set last [$slot(window).menu.custom.m index last]
    for {set i 0} {$i <= $last} {incr i} {
	catch {$menu entryconfig $i -state $state}
    }

    set dv_state($self,overflow)	[cal option AllowOverflow]
    set dv_state($self,ampm)		[cal option AmPm]
    set dv_state($self,mondayfirst)	[cal option MondayFirst]
    set dv_state($self,defremind)	[cal option DefaultEarlyWarning]
}

# effects - Configure the edit menu
method DayView config_edit {} {
    set menu $slot(window).menu.edit.m

    global dv_state
    if {$dv_state(clipboard) == ""} {
	$menu entryconfig {Paste} -state disabled
    } else {
	$menu entryconfig {Paste} -state normal
    }

    if [cal readonly] {
	$menu entryconfig {Import Selection} -state disabled
    } else {
	$menu entryconfig {Import Selection} -state normal
    }
}
