Viewing contents of file '../idllib/astron/pro/dbedit.pro'
;+
; NAME:
;	DBEDIT
;
; PURPOSE:
;	Interactively edit specified fields in a database. 
; EXPLANATION:
;	The value of each field is displayed, and the user has the option
;	of changing or keeping the value.  Widgets will be used if they
;	are available.
;
; CALLING SEQUENCE:
;	dbedit, list, [ items ]
;
; INPUTS:
;	list - scalar or vector of database entry numbers.  Set list = 0 to 
;	interactively add a new entry to a database.  Set list = -1 to edit 
;	all entries.
;
; OPTIONAL INPUTS:
;	items - list of items to be edited.  If omitted, all fields can be 
;		edited.      
;
; COMMON BLOCKS:
; 	DB_COM -- contains information about the opened database.
;  	DBW_C -- contains information intrinsic to this program.
;
; SIDE EFFECTS:
;  	Will update the database files.
;
; RESTRICTIIONS:
;  	Database must be opened for update prior to running
;  	this program.  User must be running DBEDIT from an 
;  	account that has write privileges to the databases.  
;
;	If one is editing an indexed item, then after all edits are complete,
;	DBINDEX will be called to reindex the entire item.    This may
;	be time consuming.
;
;	Cannot be used to edit items with multiple values
;
; EXAMPLE:
;	Suppose one had new parallaxes for all stars fainter than 5th magnitude
;	in the Yale Bright Star Catalog and wanted to update the PRLAX and
;	PRLAX_CODE fields with these new numbers
;
;	IDL> !priv=2			
;	IDL> dbopen, 'yale_bs', 1            ;Open catalog for update
;	IDL> list = dbfind( 'v>5')     ;Find fainter than 5th magnitude
;	IDL> dbedit, list, 'prlax, prlax_code'   ;Manual entry of new values
;
; PROCEDURE:
;	(1) Use the cursor and point to the value you want to edit.   
;	(2) Type the new field value over the old field value.
;	(3) When you are done changing all of the field values for each entry
;	save the entry to the databases by pressing 'SAVE ENTRY TO DATABASES'.
;	Here all of the values will be checked to see if they are the correct
;	data type.  If a field value is not of the correct data type, it will
;	not be saved.  
;
;	Use the buttons "PREV ENTRY" and "NEXT ENTRY" to move between entry 
;	numbers.  You must save each entry before going on to another entry in 
;	order for your changes to be saved.
;
;	Pressing "RESET THIS ENTRY" will remove any unsaved changes to the 
;	current entry.
;
;REVISION HISTORY:
;	Adapted from Landsman's DBEDIT
;	added widgets,  Melissa Marsh, HSTX, August 1993
;	do not need to press return after entering each entry,
;			fixed layout problem on SUN,
;			Melissa Marsh, HSTX, January 1994
;	Only updates the fields which are changed. Joel Offenberg, HSTX, Mar 94
;	Corrected test for changed fields  Wayne Landsman  HSTX, Mar 94
;	Removed a couple of redundant statements W. Landsman HSTX Jan 96
;	Converted to IDL V5.0   W. Landsman   September 1997
;-


;----------------------------------------------------------------

;event handler for ACKNOWLEDGE BUTTON

pro acknow_event,ev
widget_control,ev.id,GET_VALUE=value
if (value EQ 'ACKNOWLEDGED') then $
        widget_control,/DESTROY,ev.top
end

;----------------------------------------------------------------


;event handler for main part of program

pro widgetedit_event,event

common db_com,qdb,QITEMS,QDBREC

common dbw_c,liston,main,holder,widlabel,widtext,middle,nitems,names,$
        it,itnum,dtype,numvals,sbyte,nbytes,buts,prevbut,but2,resetbut,$
        endbut,nextbut,mid,minlist,maxlist,savebut,bigmid,entry,wid_warn,$
       	holder0,widtext0,widlabel0,thislist,nlist,wereat,newflag

CASE event.id OF

    endbut: widget_control,event.top,/destroy ;destory main widget--end session

    prevbut:begin	;go to previous entry
	if wereat ne 0 then wereat= wereat-1
	liston = thislist[wereat]
	widedit
    end

    nextbut:begin  	;go to next entry
	if wereat lt nlist-1 then wereat = wereat+1 else $
              widget_control,event.top,/destroy          ;end session
	liston = thislist[wereat]
	widedit
    end

    resetbut:begin	;reset this entry
	liston = liston
	widedit	
    end

    savebut: begin	;save entry to databases
	  ;update database
 	for i = 0, nitems -1 do begin
	  widget_control,widtext[i],get_value=val
	  ;test value
	  valid = 0
           oldval = dbxval(entry,dtype[i],numvals[i],sbyte[i],nbytes[i])

	  on_ioerror,BADVAL
	  IF (strtrim(oldval[0],2) ne (strtrim(val[0],2))) THEN BEGIN
	      oldval[0] = strtrim(val,2)
	      valid = 1
	      dbxput,oldval,entry,dtype[i],sbyte[i],nbytes[i]
	      print,strcompress('Entry ' + string(liston) +':  '  + $
              names[i] + ' = ' + string(val))
              newflag[ wereat, i ] = 1b
    BADVAL: 	if (not valid) then begin
	    	bad_base = widget_base(/column,title='Bad Value')
	    	m = 'Item '+ strcompress(names[i],/rem) + $ 
			' must be of type ' + datatype(oldval[0],1)
	    	w1 = widget_label( bad_base,value=m )
	    	w2 = widget_button( bad_base,value='ACKNOWLEDGED' )
	    	widget_control,bad_base,/realize
	    	xmanager,'acknow',bad_base,/modal
	    	str = dbxval(entry,dtype[i],numvals[i],sbyte[i],nbytes[i])
	    	str = '    '+string(str[0])
	    	widget_control,widtext[i],set_value=str		
	  	endif
	  endIF 
	  on_ioerror,NULL
	endfor
	
	if (liston EQ 0) then begin
                 dbwrt,entry,0,1	;new entry
        endif else begin
                 dbwrt,entry
        endelse
	widedit
	;create widget telling the user that the changes have been made.
    end

    else: ;donothing
   
     endcase
end

;--------------------------------------------------------------------
pro widedit
;program that makes "middle" of main widget (field values)


common db_com,qdb,QITEMS,QDBREC
                           

common dbw_c,liston,main,holder,widlabel,widtext,middle,nitems,names,$
	it,itnum,dtype,numvals,sbyte,nbytes,buts,prevbut,but2,resetbut,$
	endbut,nextbut,mid,minlist,maxlist,savebut,bigmid,entry,wid_warn,$
	holder0,widtext0,widlabel0,thislist,nlist,wereat,newflag


;get entry number
 dbrd, liston, entry

;get field values for this entry
 widget_control, widtext0, set_value=string(liston)
 for i = 0,nitems-1 do begin
        str = dbxval(entry,dtype[i],numvals[i],sbyte[i],nbytes[i])
        str = '    '+string(str[0])
	widget_control,widtext[i],set_value=str
 endfor

;check to see if this entry is the minimum or maximum entry 
 if (liston EQ minlist) then widget_control,prevbut,sensitive=0 else $
		widget_control,prevbut,sensitive=1 
 if (liston EQ maxlist) then widget_control,nextbut,sensitive=0 else $
		widget_control,nextbut,sensitive=1

 end
;-------------------------------------------------------------------------
;main program

pro dbedit,list,items

common db_com,qdb,QITEMS,QDBREC

;Nitems - Number elements in input list
;Thislist - Sorted list of entry numbers
;Minlist - Minimum input entry number
;Maxlist - Maximum input entry number
;Liston - The current entry number being edited (scalar)
;wereat - The index of ThisList vector being edited, i.e. Thislist(wereat)=LIston
;dtype - data type(s) (1=string,2=byte,4=i*4,...)
;sbyte - starting byte(s) in entry
;numvals - number of data values for item(s)
;    NOTE: dtype, sbyte, numvals are dimensioned for *all* entries 

common dbw_c,liston,main,holder,widlabel,widtext,middle,nitems,names,$
	it,itnum,dtype,numvals,sbyte,nbytes,buts,prevbut,but2,resetbut,$
        endbut,nextbut,mid,minlist,maxlist,savebut,bigmid,entry,wid_warn,$
	holder0,widtext0,widlabel0,thislist,nlist,wereat,newflag
                          
 On_error,2
 if N_params() LT 1 then begin
	print,'Syntax - dbedit, list, [ items ]'
	return
 endif
	
;make sure widgets are available
 if (!D.FLAGS AND 65536) EQ 0 then begin  
	dbedit_basic, list, items
        return
 endif

;check to make sure database is open
w1 = widget_base(/column)
    ;first check to see if there is an open database
    s = size(qdb)
    if (s[0] EQ 0) then begin
    no_open = widget_base(/column,title='NO DATABASE OPEN')
    	m1 = 'No open database currently exists.'
    	w1 = widget_label(no_open,VALUE=m1)
    	w2 = widget_button(no_open,VALUE='ACKNOWLEDGED')
    	widget_control, no_open, /realize
    	xmanager, 'acknow', no_open, /modal
	goto, PROEND  
    endif
;check to make sure the database is opened for update
    dbname = db_info('NAME',0)
    if not db_info('UPDATE') then begin

    	no_open = widget_base(/column,title='NOT OPEN FOR UPDATE')	 
    	m1 = 'Database ' + dbname + ' must be opened for update.'
    	w1 = widget_label(no_open,VALUE=m1)
        w2 = widget_button(no_open,VALUE='ACKNOWLEDGED')
        widget_control,no_open,/realize
        xmanager,'acknow',no_open,/MODAL
	goto,PROEND

    endif


    ;check parameters
    zparcheck, 'DBEDIT', list, 1, [1,2,3], [0,1], 'Database entry numbers'

    ;get items.  If items not specified use all items except ENTRY
    if ( N_params() LT 2 ) then begin       
    	nitems = db_info('ITEMS',0) -1       
    	items = indgen(nitems) + 1
    endif

    nlist = N_elements(list)

    if nlist gt 1 then begin ;sort entry numbers

   	sar = sort(list)
   	thislist = list[sar]

    endif else begin

	thislist = intarr(1) 
	thislist[0] = list

    endelse

    ;edit all entries?  get number of entries
    if ( list[0] EQ -1 ) then begin          
    	nlist = db_info('ENTRIES',0)           
        if nlist le 0 then begin
           print,'Empty database cannot be edited. Use list=0 to add new entry'
           goto, PROEND
        endif
    	thislist = lindgen(nlist) + 1
    endif

    minlist = min(thislist)
    maxlist = max(thislist)


    nentry = db_info('ENTRIES',0)
    if (maxlist gt nentry) then begin
    	m = dbname + ' entry numbers must be less than ' + strtrim(nentry+1,2)
	wrongno = widget_base(/column,title='NOT VALID ENTRY NUMBER')
	w1 = widget_label( wrongno, VALUE=m)
        w2 = widget_button( wrongno, VALUE='ACKNOWLEDGED')
        widget_control, wrongno, /realize
        xmanager, 'acknow', wrongno, /modal
	goto, PROEND
    endif

    nitems = db_info('ITEMS',0) -1
    allitems = indgen(nitems) + 1

    ;get information about items
    db_item,allitems,itnum,ivalnum,dtype,sbyte,numvals,nbytes
    nvalues = db_item_info('nvalues')

    db_item,items,it

    nit = n_elements(it)		      ;Number of items to be edited
    names = db_item_info('name',itnum)        ;Get names of each item
    newflag = bytarr(nlist,nitems)  ;Keeps track of fields actually updated

    wereat = 0
    liston = thislist[wereat]
    dbrd,liston,entry

    ;create widget and display
    main = widget_base(/COLUMN,title='Widgetized Database Editor')
    w1 = widget_label(main,value='******  '  + dbname + '  ******')
    if !version.os EQ 'vms' then xsize=420 else xsize=325
    bigmid = widget_base(main,/column,x_scroll_size=xsize,y_scroll_size=650)


    butbase = widget_base(main,/column,/frame)
    savebut = widget_button(butbase,value='SAVE THIS ENTRY')
    buts = widget_base(butbase,/row)
    prevbut = widget_button(buts,value='<- PREV ENTRY')
    but2 = widget_base(buts,/column)
    resetbut = widget_button(but2,value='RESET THIS ENTRY')
    endbut = widget_button(but2,value='END SESSION')
    nextbut = widget_button(buts,value='NEXT ENTRY ->')

    widlabel = lonarr(nitems+1)
    widtext = lonarr(nitems+1)
    holder = lonarr(nitems+1)

    mid = widget_base(bigmid,/column)

    holder0 = widget_base(mid,/row)
    widlabel0 =widget_label(holder0,value='  ENTRY NUMBER  ',/frame)
    num = string(liston)
    widtext0 = widget_label(holder0,value=num)

    middle = widget_base(mid,/column)

    for i = 0,nitems-1 do begin
        ed = 'N'
        str1 = names[i]

	;add spaces if version is vms to make layout "look better"
	if (!version.os EQ 'vms') then begin
        	str1 = strcompress(str1,/remove_all)
        	str1len = strlen(str1)
        	b = 20.-str1len
        	n = b*2.
        	for j = 0,n do str1 = str1+' '
	endif

        for j = 0, N_elements(it)-1 do begin
                if it[j] EQ itnum[i] then ed = 'Y'
        endfor

        str = dbxval(entry,dtype[i],numvals[i],sbyte[i],nbytes[i])
        str = '    ' + string(str[0])
        if ed eq 'Y' then  begin
                holder[i] = widget_base(middle,/row)
                widlabel[i] = widget_label(holder[i],value = str1,/frame)
                widtext[i] = widget_text(holder[i],/frame,value=str,/edit)
        endif else begin
                holder[i] = widget_base(middle,/row)
                widlabel[i] = widget_label(holder[i],value = str1,/frame)
                widtext[i] = widget_label(holder[i],value=str)
        endelse	
    endfor

    if (liston EQ minlist) then widget_control,prevbut,sensitive=0 else $
                widget_control,prevbut,sensitive=1
    if (liston EQ maxlist) then widget_control,nextbut,sensitive=0 else $
                widget_control,nextbut,sensitive=1

    widget_control,main,/realize
    xmanager,'widgetedit',main

 newitem = total(newflag, 1)
 indexnum = where(newitem, nindex)

   if ( nindex GT 0 ) then begin                          ;Any mods made?
      indexnum = itnum[indexnum]
      indextype = db_item_info('INDEX',indexnum);Index type of modified fields 
      good = where(indextype GE 1, Ngood)         ;Which fields are indexed?
      if Ngood GT 0 then begin 
	message, 'Now updating index file', /INF
	dbindex, indexnum[good]
      endif
      dbopen,strlowcase(dbname),1
    endif

PROEND:

 return
 end