The R Project SVN R

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
25390 iacus 1
/*
25632 iacus 2
 *  R : A Computer Language for Statistical Data Analysis
25390 iacus 3
 *  Copyright (C) 1995, 1996  Robert Gentleman and Ross Ihaka
25632 iacus 4
 *  Copyright (C) 1997--2003  Robert Gentleman, Ross Ihaka
5
 *			      and the R Development Core Team
25390 iacus 6
 *
7
 *  This program is free software; you can redistribute it and/or modify
8
 *  it under the terms of the GNU General Public License as published by
9
 *  the Free Software Foundation; either version 2 of the License, or
10
 *  (at your option) any later version.
11
 *
12
 *  This program is distributed in the hope that it will be useful,
13
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
14
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15
 *  GNU General Public License for more details.
16
 *
17
 *  You should have received a copy of the GNU General Public License
18
 *  along with this program; if not, write to the Free Software
19
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
20
 */
21
 
22
#ifndef __AQUA_DATA_ENTRY__
23
#define __AQUA_DATA_ENTRY__
24
 
25
 
26
#ifdef HAVE_CONFIG_H
27
#include <config.h>
28
#endif
29
#include <Defn.h>
30
 
31
#include <R.h>
32
#include <R_ext/Boolean.h>
33
#include <R_ext/Rdynload.h>
34
#include <Rdefines.h>
35
#include <Rinternals.h>
36
 
37
#include "Print.h"
38
 
39
#ifdef HAVE_AQUA
26035 iacus 40
#define __DEBUGGING__
25390 iacus 41
 
42
# include <Carbon/Carbon.h>
43
 
25522 iacus 44
#include "Raqua.h"
45
 
46
extern RAquaPrefs CurrentPrefs;
47
 
25390 iacus 48
#include <limits.h>
49
 
50
 
51
#ifndef kDataBrowserListViewAppendColumn
52
#define kDataBrowserListViewAppendColumn ULONG_MAX
53
#endif
54
 
55
typedef enum { UP, DOWN, LEFT, RIGHT } DE_DIRECTION;
56
 
57
typedef enum {UNKNOWNN, NUMERIC, CHARACTER} CellType;
58
 
59
/* EXPORTS : */
60
SEXP Raqua_dataentry(SEXP call, SEXP op, SEXP args, SEXP rho);
61
 
62
 
63
static void ConfigureDataEntry(ControlRef);
64
static void CreateDataEntry(WindowRef, ControlRef*);
65
static ControlRef GetDataBrowserFromWindow(WindowRef window);
66
static void InstallDataEntryCallbacks(ControlRef);
67
 
25522 iacus 68
static CellType get_col_type(int col);
69
 
25390 iacus 70
static pascal OSStatus deGetSetItemData(ControlRef browser, 
71
    DataBrowserItemID itemID, DataBrowserPropertyID property, 
72
    DataBrowserItemDataRef itemData, Boolean changeValue);
73
 
74
static pascal void deItemNotification(
75
	ControlRef browser, 
76
	DataBrowserItemID itemID, 
77
	DataBrowserItemNotification message);
78
static pascal Boolean deItemComparison(
79
	ControlRef browser, DataBrowserItemID itemOneID, 
80
	DataBrowserItemID itemTwoID, DataBrowserPropertyID sortProperty);
25522 iacus 81
static pascal void deCustomDrawProc( ControlRef browser, DataBrowserItemID item, 
82
        DataBrowserPropertyID property, DataBrowserItemState itemState, 
83
        const Rect *theRect, SInt16 gdDepth, Boolean colorDevice);
25531 iacus 84
static pascal Boolean deCustomHitTestProc(ControlRef browser, DataBrowserItemID item, 
85
        DataBrowserPropertyID property, const Rect *theRect, const Rect *mouseRect);
86
static pascal Boolean deCustomEditTextProc(ControlRef browser, DataBrowserItemID item,
87
        DataBrowserPropertyID property, CFStringRef theString, Rect *maxEditTextRect, 
88
        Boolean *shrinkToFit);
25390 iacus 89
 
25522 iacus 90
 
25531 iacus 91
 
25390 iacus 92
pascal OSStatus deEventHandler(EventHandlerCallRef, EventRef, void*);
93
 
94
 
95
Boolean OpenDataEntry(void);
96
void CloseDataEntry(void);
97
 
98
 
99
Boolean isDataEntryOpen = false;
100
WindowRef DataEntryWindow = NULL;
101
ControlRef DataEntryControl = NULL;
25522 iacus 102
CGContextRef		deContext;
25390 iacus 103
 
104
int NumOfRows=0;
25522 iacus 105
DataBrowserItemID *RowID;
25390 iacus 106
 
107
static SEXP work, names, lens;
108
static PROTECT_INDEX wpi, npi, lpi;
109
static SEXP ssNA_STRING;
110
static double ssNA_REAL;
111
 
112
static SEXP ssNewVector(SEXPTYPE, int);
25749 iacus 113
extern bool		DataEntryFinished;
25786 iacus 114
extern void Raqua_ProcessEvents(void);
25390 iacus 115
 
116
extern TXNControlTag	RReadOnlyTag[];
117
extern TXNControlData   RReadOnlyData[];
118
extern TXNObject	RConsoleInObject;
119
 
120
static char *get_col_name(int col);
121
static int xmaxused, ymaxused;
122
 
123
 
124
 
125
 
126
 
127
/*
128
  Underlying assumptions (for this version R >= 1.8.0)
129
 
130
  The data are stored in a list `work', with unused columns having
131
  NULL entries.  The names for the list are in `names', which should
132
  have a name for all displayable columns (up to xmaxused). 
133
  The *used* lengths of the columns are in `lens': this needs only be
134
  set for non-NULL columns.
135
 
136
  If the list was originally length(0), that should work with 
137
 
138
 
139
  All row and col numbers are 1-based.
140
 
141
  BDR May 2003
142
 */
143
 
144
/*
145
   The spreadsheet function returns a list of vectors. The types of
146
   these vectors can be specified by the user as can their names. It
147
   the names are specified they are set during initialization. The
148
   user can change these via a menu interface, they can also change
149
   the type.
150
 
151
   The vectors are created too long and if they need to be increased
152
   this is done by using the next higher power of 2. They start 100
153
   long. To cut them to the correct length for return you need to know
154
   the largest row number that was assigned to. LEVELS (sxpinfo.gp) is
155
   used to keep track of this, separately for each vector. Vectors are
156
   initialized to NA when they are created so that NA is returned for
157
   any cell that was not set by the user.  So that coercion back and
158
   forth maintains values of ssNA_REAL and ssNA_STRING I have set
159
   ssNA_STRING to be coerceVector(ssNA_REAL), very weird but easy.
160
 
161
   In Macintosh we needed to call the main event loop to get
162
   events. This ensures that the spreadsheet interacts well with the
163
   other windows. Under X windows we let the window manager handle
164
   those sorts of details.
165
 
166
 */
167
 
168
 
169
/*
170
   ssNewVector is just an interface to allocVector but it lets us
171
   set the fields to NA. We need to have a special NA for reals and
172
   strings so that we can differentiate between uninitialized elements
173
   in the vectors and user supplied NA's; hence ssNA_REAL and ssNA_STRING
174
 */
175
 
176
static SEXP ssNewVector(SEXPTYPE type, int vlen)
177
{
178
    SEXP tvec;
179
    int j;
180
 
181
    tvec = allocVector(type, vlen);
182
    for (j = 0; j < vlen; j++)
183
	if (type == REALSXP)
184
	    REAL(tvec)[j] = ssNA_REAL;
185
	else if (type == STRSXP)
186
	    SET_STRING_ELT(tvec, j, STRING_ELT(ssNA_STRING, 0));
187
    SETLEVELS(tvec, 0);
188
    return (tvec);
189
}
190
 
191
 
192
 
193
 
194
 
195
 
196
 
197
Rect deBounds = { 400, 400, 600, 800 };
198
 
199
/*
200
  id : integer, id number in the browser
201
  isroot : boolean, this id is a root item
202
  iscont : boolean, is container?
203
  numofit : integer, number of items
204
  parid   : parent id number
205
  name   : char, name of objects
206
  type   : type, class or mode
207
  objsize: can be dim, length or number of levels 
208
*/
209
 
210
/* The following are local copies of the above */
211
 
212
                                /* We do not check for this */ 
213
void EmptyDataEntry(void);
214
 
215
 
216
 
217
 
218
 
219
static const EventTypeSpec	RCloseWinEvent[] = 
220
{
221
        { kEventClassWindow, kEventWindowClose }        
222
};
223
 
224
extern OSStatus DoCloseHandler( EventHandlerCallRef inCallRef, EventRef inEvent, void* inUserData );
225
 
226
 
227
 
228
 
229
Boolean OpenDataEntry(void)
230
{
231
	OSStatus err = noErr;
232
	int i,j,k;
25696 iacus 233
        Rect	bounds;
25531 iacus 234
        EventTypeSpec deEvents[] = {
25390 iacus 235
		{ kEventClassCommand,	kEventCommandProcess }, 
236
		{ kEventClassCommand,	kEventCommandUpdateStatus }, 
237
		{ kEventClassWindow,	kEventWindowGetIdealSize },
238
		{ kEventClassWindow,	kEventWindowBoundsChanged }, 
25531 iacus 239
		{ kEventClassWindow,	kEventWindowGetClickActivation},
240
/*                { kEventClassMouse,	kEventMouseDown} */
241
        };
25390 iacus 242
 
243
     CreateNewWindow(kDocumentWindowClass,  kWindowStandardHandlerAttribute |
244
            kWindowStandardDocumentAttributes, &deBounds, &DataEntryWindow);
245
 
246
    if(DataEntryWindow == NULL)
247
     return(FALSE);
248
 
25522 iacus 249
     CreateCGContextForPort( GetWindowPort(DataEntryWindow), &deContext );
250
 
25390 iacus 251
     InstallWindowEventHandler(DataEntryWindow, 
252
    		NewEventHandlerUPP(deEventHandler), 
253
    		sizeof(deEvents)/sizeof(EventTypeSpec), deEvents, NULL, NULL);
254
 
255
     InstallWindowEventHandler( DataEntryWindow, NewEventHandlerUPP(DoCloseHandler), 
256
                                          1,
257
                                          RCloseWinEvent, (void *)DataEntryWindow, NULL);
258
 
259
 
260
     SetWindowTitleWithCFString(DataEntryWindow, CFSTR("R DataEntryWindow"));
261
 
262
 
263
 
264
    /* Create the DataBrowser */
265
     CreateDataEntry(DataEntryWindow, &DataEntryControl);
266
    /* Configure the DataBrowser */
267
 
268
    ConfigureDataEntry(DataEntryControl);
269
    err = SetDataBrowserTarget(DataEntryControl, 1);
270
 
271
    /* Set the keyboard focus */
272
	SetKeyboardFocus(DataEntryWindow, DataEntryControl, kControlDataBrowserPart);
273
 
274
	/* Store DB as a window property */
275
    SetWindowProperty(DataEntryWindow,'RMAC', 'RDEY',sizeof(DataEntryControl), &DataEntryControl);
276
 
277
	InstallDataEntryCallbacks(DataEntryControl);
278
 
279
 
280
 
281
	if(DataEntryControl == NULL){              
282
	 CloseDataEntry();	 
283
	 return;
284
	}
285
 
25522 iacus 286
 
25390 iacus 287
   NumOfRows = ymaxused;	
25522 iacus 288
   RowID = (DataBrowserItemID*)malloc(NumOfRows * sizeof(DataBrowserItemID));
25390 iacus 289
   for(i=1;i<=NumOfRows;i++)
290
    RowID[i-1] = i;
291
 
292
  AddDataBrowserItems(DataEntryControl, kDataBrowserNoItem, 
293
				NumOfRows, RowID, kDataBrowserItemNoProperty);
294
 
295
 
296
 
25531 iacus 297
    SetDataBrowserSelectionFlags( DataEntryControl, kDataBrowserSelectOnlyOne );
25522 iacus 298
//SetAutomaticControlDragTrackingEnabledForWindow( DataEntryWindow, true );	
25390 iacus 299
    ShowWindow(DataEntryWindow);
300
 
25696 iacus 301
    GetPortBounds(GetWindowPort(DataEntryWindow), &bounds);
302
    SizeControl(DataEntryControl, bounds.right - bounds.left, bounds.bottom - bounds.top);
25390 iacus 303
 
304
}
305
 
306
 
307
 
308
void EmptyDataEntry(void)
309
{
310
  RemoveDataBrowserItems (DataEntryControl, kDataBrowserNoItem, 0, 
311
          NULL, kDataBrowserItemNoProperty);
312
} 
313
 
314
void CloseDataEntry(void)
315
{
316
 
317
    if(DataEntryWindow){
318
     if( GetWindowBounds(DataEntryWindow,kWindowStructureRgn,&deBounds) != noErr)
319
      SetRect(&deBounds, 400, 400, 600, 800);
320
    }
321
    else 
322
     SetRect(&deBounds, 400, 400, 600, 800);
323
 
324
 
25522 iacus 325
    CGContextRelease( deContext );    
25390 iacus 326
    DisposeWindow(DataEntryWindow);
327
    DataEntryWindow = NULL;
328
 
329
 
330
    DataEntryControl = NULL;
331
    if(RowID)
332
     free(RowID);
333
 
334
} 
335
 
336
static void CreateDataEntry(WindowRef window, ControlRef *browser)
337
{
338
    Rect bounds;
339
    Boolean frameAndFocus = false;
340
 
341
    /* Create a DataBrowser */
342
    GetWindowBounds(window, kWindowContentRgn, &bounds);
343
 
344
    bounds.top = bounds.left = 0;
345
    bounds.right = bounds.right - bounds.left;
346
    bounds.bottom = bounds.bottom - bounds.top;
347
 
348
    CreateDataBrowserControl(window, 
349
    	&bounds, kDataBrowserListView, browser);
350
 
351
    /* Turn off DB's focus frame */
352
	SetControlData(
353
		*browser, kControlNoPart, 
354
		kControlDataBrowserIncludesFrameAndFocusTag,
355
		sizeof(frameAndFocus), &frameAndFocus);
356
}
357
 
358
 
359
static void ConfigureDataEntry(ControlRef browser)
360
{
361
	Rect insetRect;
362
	DataBrowserViewStyle viewStyle;
363
        int i;
364
 
365
	GetDataBrowserViewStyle(browser, &viewStyle);
366
 
367
	GetDataBrowserScrollBarInset(browser, &insetRect);
368
 
369
	insetRect.right = 16 - 1;
370
	SetDataBrowserScrollBarInset(browser, &insetRect);
371
 
372
	switch (viewStyle)
373
	{
374
		case kDataBrowserListView:
375
		{	DataBrowserListViewColumnDesc columnDesc;
376
 
377
                        columnDesc.headerBtnDesc.titleOffset = 0;
378
 
379
			columnDesc.headerBtnDesc.version = 
380
				kDataBrowserListViewLatestHeaderDesc;
381
 
382
			columnDesc.headerBtnDesc.btnFontStyle.flags	= 
383
				kControlUseFontMask | kControlUseJustMask;
384
 
385
			columnDesc.headerBtnDesc.btnContentInfo.contentType = kControlNoContent;
386
 
387
                        columnDesc.headerBtnDesc.minimumWidth = 30;
388
			columnDesc.headerBtnDesc.maximumWidth = 200;
389
 
390
			columnDesc.headerBtnDesc.btnFontStyle.just = teFlushRight;
391
 
392
			columnDesc.headerBtnDesc.btnFontStyle.font = kControlFontViewSystemFont;
393
			columnDesc.headerBtnDesc.btnFontStyle.style = normal;
394
 
25531 iacus 395
			columnDesc.propertyDesc.propertyType = kDataBrowserCustomType;
25390 iacus 396
			columnDesc.propertyDesc.propertyFlags = kDataBrowserPropertyIsMutable |									  		kDataBrowserListViewDefaultColumnFlags;
397
			for(i=0;i<=xmaxused;i++){
398
 
25531 iacus 399
			columnDesc.propertyDesc.propertyID = i+2000;
400
			if(i>=0) columnDesc.propertyDesc.propertyType = kDataBrowserTextType;
25390 iacus 401
			//columnDesc.headerBtnDesc.btnContentInfo.contentType = kControlContentIconRef;
402
 
403
                        if(i==0)
404
                          columnDesc.headerBtnDesc.titleString = CFStringCreateWithCString(
405
				CFAllocatorGetDefault(),"Row Labels", kCFStringEncodingMacRoman);
406
                        else
407
                         columnDesc.headerBtnDesc.titleString = CFStringCreateWithCString(
408
				CFAllocatorGetDefault(), get_col_name(i), kCFStringEncodingMacRoman);
409
 
410
			AddDataBrowserListViewColumn(browser, 
411
				&columnDesc, kDataBrowserListViewAppendColumn);
412
 
413
 
414
			SetDataBrowserListViewDisclosureColumn(browser, columnDesc.propertyDesc.propertyID, false);
415
                        }
416
 
417
 
418
 
419
//			ReleaseIconRef(columnDesc.headerBtnDesc.btnContentInfo.u.iconRef);
420
		}	break;
421
	}
422
       }
423
 
424
 
425
static ControlRef GetDataBrowserFromWindow(WindowRef window)
426
{
427
	ControlRef browser = NULL;
428
 
429
	if (window != NULL)
430
		GetWindowProperty(window, 'RMAC', 
431
		'RDEY', sizeof(browser), NULL, &browser);
432
 
433
	return browser;
434
}
435
 
436
 
437
void InstallDataEntryCallbacks(ControlRef browser)
438
{
439
    DataBrowserCallbacks myCallbacks;
25522 iacus 440
    DataBrowserCustomCallbacks dbCustomCallbacks;
25390 iacus 441
 
442
    myCallbacks.version = kDataBrowserLatestCallbacks;
443
    InitDataBrowserCallbacks(&myCallbacks);
444
 
445
    myCallbacks.u.v1.itemDataCallback = 
446
        NewDataBrowserItemDataUPP(deGetSetItemData);
447
 
448
 
449
    myCallbacks.u.v1.itemNotificationCallback = 
450
        NewDataBrowserItemNotificationUPP(deItemNotification);
451
 
452
    myCallbacks.u.v1.itemCompareCallback = 
453
		NewDataBrowserItemCompareUPP(deItemComparison);
25522 iacus 454
 
455
    SetDataBrowserCallbacks(browser, &myCallbacks);
25390 iacus 456
 
25522 iacus 457
    dbCustomCallbacks.version	= kDataBrowserLatestCallbacks;
458
    InitDataBrowserCustomCallbacks( &dbCustomCallbacks );
25531 iacus 459
    dbCustomCallbacks.u.v1.drawItemCallback = NewDataBrowserDrawItemUPP( deCustomDrawProc );
460
    dbCustomCallbacks.u.v1.hitTestCallback = NewDataBrowserHitTestUPP( deCustomHitTestProc );
461
    dbCustomCallbacks.u.v1.editTextCallback = NewDataBrowserEditItemUPP( deCustomEditTextProc );
462
 
463
    SetDataBrowserCustomCallbacks(browser, &dbCustomCallbacks);
25522 iacus 464
 
25390 iacus 465
}
466
 
467
 
468
 
469
 
470
 
471
void printelt(SEXP invec, int vrow, char *str);
472
 
473
 
474
static pascal OSStatus deGetSetItemData(ControlRef browser, 
475
    DataBrowserItemID itemID, DataBrowserPropertyID property, 
476
    DataBrowserItemDataRef itemData, Boolean changeValue)
477
{
478
#pragma unused (browser)
479
	Str255 pascalString;
480
	OSStatus err = noErr;
481
        CFStringRef text,value;
482
	SEXP tmp;
25487 iacus 483
        int i,col,row=-1;
25390 iacus 484
        char buf[1000];
485
 
25531 iacus 486
	  if(property>=2000 & property<10000){
487
          col = property-2000;
25390 iacus 488
          row = itemID;
489
         }
490
 
491
        if(!changeValue) {
492
 
493
 
25531 iacus 494
         if(property==2000){
25390 iacus 495
             sprintf(buf,"%d",row);
496
             CopyCStringToPascal(buf,pascalString);
497
             text = CFStringCreateWithPascalString(CFAllocatorGetDefault(), pascalString, kCFStringEncodingMacRoman);
498
             err = SetDataBrowserItemDataText(itemData, text); 
499
             CFRelease(text); 
500
         }
501
 
25531 iacus 502
         if(property>2000 & row>0 & row<=ymaxused){          
25390 iacus 503
          tmp = VECTOR_ELT(work, col-1);
504
          if (!isNull(tmp)) {
505
             strcpy(buf,"     ");
506
             if(LENGTH(tmp)>row-1)
507
              printelt(tmp, row-1, buf);
508
             } 
509
             CopyCStringToPascal(buf,pascalString);
510
             text = CFStringCreateWithPascalString(CFAllocatorGetDefault(), pascalString, kCFStringEncodingMacRoman);
511
             err = SetDataBrowserItemDataText(itemData, text); 
512
             CFRelease(text); 
513
 
514
 
515
        }   
516
        switch (property)
517
	{
518
		case kDataBrowserItemIsEditableProperty:
519
		{	err = SetDataBrowserItemDataBooleanValue(itemData, true);
520
		}	break;
521
 
522
 
523
 
524
		default:
525
		{	err = errDataBrowserPropertyNotSupported;
526
		}	break;
527
	}
25721 tlumley 528
	}
25390 iacus 529
	else {
530
 
25531 iacus 531
          if(property>2000 & row>0 & row<=ymaxused){          
25390 iacus 532
            err = GetDataBrowserItemDataText(itemData, &text); 
533
            CFStringGetCString (text, buf, 1000,  kCFStringEncodingMacRoman);
534
            if(strlen(buf)>0){
535
                tmp = VECTOR_ELT(work, col-1);
536
                    if(get_col_type(col) == CHARACTER)
537
                        SET_STRING_ELT(tmp, row-1, mkChar(buf));
538
                    else {
539
                        char *endp;
540
                        double new = R_strtod(buf, &endp);
541
                        if(isBlankString(endp))
542
                            REAL(tmp)[row - 1] = new;
543
                    }
544
             } else { 
545
                if(get_col_type(col) == CHARACTER)
546
                    SET_STRING_ELT(tmp, row - 1, NA_STRING);
547
                else
548
                    REAL(tmp)[row - 1] = NA_REAL;
549
            }
25721 tlumley 550
	    SetWindowModified(DataEntryWindow, true);
25390 iacus 551
            CFRelease(text); 
552
          }             
553
 
554
 
555
 
556
	}
557
 
558
	return err;
559
}
560
 
561
 
562
void printelt(SEXP invec, int vrow, char *strp)
563
{
564
 
565
    if(!strp)
566
     return;
567
 
568
 
569
    PrintDefaults(R_NilValue);
570
    if (TYPEOF(invec) == REALSXP) {
571
	if (REAL(invec)[vrow] != ssNA_REAL) {
572
	    strcpy(strp, EncodeElement(invec, vrow, 0));
573
	    return;
574
	}
575
    }
576
    else if (TYPEOF(invec) == STRSXP) {
577
    if(CHAR(STRING_ELT(invec, vrow))){
578
	if (!streql(CHAR(STRING_ELT(invec, vrow)),
579
		    CHAR(STRING_ELT(ssNA_STRING, 0)))) {
580
	    strcpy(strp, EncodeElement(invec, vrow, 0));
581
	    return;
582
	}
583
    }
584
    }
585
    else
586
	error("dataentry: internal memory error");
587
}
588
 
589
 
590
 static pascal void deItemNotification(
591
	ControlRef browser, 
592
	DataBrowserItemID itemID, 
593
	DataBrowserItemNotification message)
594
{
595
	UInt32 i;
596
	UInt32 numSelectedItems;
597
	UInt16 j;
598
        OSStatus err;
599
        DataBrowserItemID tempid;
600
         CFMutableStringRef text;
601
         char buf[1000];
25531 iacus 602
 
25390 iacus 603
	switch (message)
604
	{
605
		case kDataBrowserItemSelected:
606
		{	Handle handle = NewHandle(0);
607
			GetDataBrowserItems(browser, 
608
				kDataBrowserNoItem, true, kDataBrowserItemIsSelected, handle);
609
		    numSelectedItems = GetHandleSize(handle)/sizeof(DataBrowserItemID);
25531 iacus 610
              // fprintf(stderr,"\n notif. id=%d",itemID);       
25390 iacus 611
            	}	
612
                break;
613
 
614
 
615
	}
616
}
617
 
25531 iacus 618
Boolean MouseClicked = false;
619
 
25390 iacus 620
pascal OSStatus deEventHandler(
621
	EventHandlerCallRef a, EventRef inEvent, void*b)
622
{
623
    OSStatus result = noErr;
25531 iacus 624
    EventRef	REvent;
625
 
25390 iacus 626
	switch (GetEventClass(inEvent))
627
	{
628
    	default:
629
    	{	result = eventNotHandledErr;
630
    	}	break;
631
 
632
 
633
 
25531 iacus 634
	    case kEventClassMouse:
635
             if( GetEventKind(inEvent) == kEventMouseDown){
636
             if(!MouseClicked){
637
              MouseClicked = true;
638
              result = eventNotHandledErr;
639
             } 
640
 
641
 
642
             }
643
            break;
644
 
645
            case kEventClassWindow:
25390 iacus 646
		{
647
		    WindowRef window = NULL;
648
			GetEventParameter(inEvent, 
649
		        kEventParamDirectObject, typeWindowRef, 
650
		        NULL, sizeof(window), NULL, &window);
651
 
652
		    switch (GetEventKind(inEvent))
653
		 	{
654
		    	default:
655
		    	{	result = eventNotHandledErr;
656
		    	}	break;
657
 
658
 
659
                        case kEventWindowBoundsChanged:
660
		    	{	ControlRef browser = GetDataBrowserFromWindow(window);
661
		    		Rect bounds; GetPortBounds(GetWindowPort(window), &bounds);
662
		        	SizeControl(browser, bounds.right - bounds.left, bounds.bottom - bounds.top);
663
		    	}	break;
664
 
665
 
666
 
667
			}
668
		}	break;
669
	}
670
 
671
    return result;
672
}
673
 
674
SEXP Raqua_dataentry(SEXP call, SEXP op, SEXP args, SEXP rho)
675
{
676
    SEXP colmodes, tnames, tvec, tvec2, work2;
677
    SEXPTYPE type;
678
    int i, j, cnt, len, nprotect;
679
    RCNTXT cntxt;
680
    char clab[25];
681
 
682
    nprotect = 0;/* count the PROTECT()s */
683
    PROTECT_WITH_INDEX(work = duplicate(CAR(args)), &wpi); nprotect++;
684
    colmodes = CADR(args);
685
    tnames = getAttrib(work, R_NamesSymbol);
686
 
687
    if (TYPEOF(work) != VECSXP || TYPEOF(colmodes) != VECSXP)
688
	errorcall(call, "invalid argument");
689
 
690
    /* initialize the constants */
691
 
692
    ssNA_REAL = -NA_REAL;
693
    tvec = allocVector(REALSXP, 1);
694
    REAL(tvec)[0] = ssNA_REAL;
695
    PROTECT(ssNA_STRING = coerceVector(tvec, STRSXP)); nprotect++;
25522 iacus 696
 
25390 iacus 697
    /* setup work, names, lens  */
698
    xmaxused = length(work); ymaxused = 0;
699
    PROTECT_WITH_INDEX(lens = allocVector(INTSXP, xmaxused), &lpi);
700
    nprotect++;
701
 
702
    if (isNull(tnames)) {
703
	PROTECT_WITH_INDEX(names = allocVector(STRSXP, xmaxused), &npi);
704
	for(i = 0; i < xmaxused; i++) {
705
	    sprintf(clab, "var%d", i);
706
	    SET_STRING_ELT(names, i, mkChar(clab));
707
	}
708
    } else
709
	PROTECT_WITH_INDEX(names = duplicate(tnames), &npi);
710
    nprotect++;
711
 
712
    for (i = 0; i < xmaxused; i++) {
713
	int len = LENGTH(VECTOR_ELT(work, i));
714
	INTEGER(lens)[i] = len;
715
	ymaxused = max(len, ymaxused);
716
        type = TYPEOF(VECTOR_ELT(work, i));
25522 iacus 717
    if (LENGTH(colmodes) > 0 && !isNull(VECTOR_ELT(colmodes, i)))
25390 iacus 718
	    type = str2type(CHAR(STRING_ELT(VECTOR_ELT(colmodes, i), 0)));
719
	if (type != STRSXP) type = REALSXP;
720
	if (isNull(VECTOR_ELT(work, i))) {
721
	    if (type == NILSXP) type = REALSXP;
722
	    SET_VECTOR_ELT(work, i, ssNewVector(type, 100));
723
	} else if (!isVector(VECTOR_ELT(work, i)))
724
	    errorcall(call, "invalid type for value");
725
	else {
726
	    if (TYPEOF(VECTOR_ELT(work, i)) != type)
727
		SET_VECTOR_ELT(work, i, 
728
			       coerceVector(VECTOR_ELT(work, i), type));
729
	}
730
    }
731
 
732
 
733
    /* start up the window, more initializing in here */
734
 
735
    TXNSetTXNObjectControls(RConsoleInObject, false, 1, RReadOnlyTag, RReadOnlyData);
25749 iacus 736
    DataEntryFinished = false;
25390 iacus 737
    OpenDataEntry();
25749 iacus 738
    while(!DataEntryFinished)
25752 iacus 739
        Raqua_ProcessEvents();
25390 iacus 740
 
741
    /* drop out unused columns */
742
    for(i = 0, cnt = 0; i < xmaxused; i++)
743
	if(!isNull(VECTOR_ELT(work, i))) cnt++;
744
    if (cnt < xmaxused) {
745
	PROTECT(work2 = allocVector(VECSXP, cnt)); nprotect++;
746
	for(i = 0, j = 0; i < xmaxused; i++) {
747
	    if(!isNull(VECTOR_ELT(work, i))) {
748
		SET_VECTOR_ELT(work2, j, VECTOR_ELT(work, i));
749
		INTEGER(lens)[j] = INTEGER(lens)[i];
750
		SET_STRING_ELT(names, j, STRING_ELT(names, i));
751
		j++;
752
	    }
753
	}
754
	REPROTECT(names = lengthgets(names, cnt), npi);
755
    } else work2 = work;
756
 
757
    for (i = 0; i < LENGTH(work2); i++) {
758
	len = INTEGER(lens)[i];
759
	tvec = VECTOR_ELT(work2, i);
760
	if (LENGTH(tvec) != len) {
761
	    tvec2 = ssNewVector(TYPEOF(tvec), len);
762
	    for (j = 0; j < len; j++) {
763
		if (TYPEOF(tvec) == REALSXP) {
764
		    if (REAL(tvec)[j] != ssNA_REAL)
765
			REAL(tvec2)[j] = REAL(tvec)[j];
766
		    else
767
			REAL(tvec2)[j] = NA_REAL;
768
		} else if (TYPEOF(tvec) == STRSXP) {
769
		    if (!streql(CHAR(STRING_ELT(tvec, j)),
770
				CHAR(STRING_ELT(ssNA_STRING, 0))))
771
			SET_STRING_ELT(tvec2, j, STRING_ELT(tvec, j));
772
		    else
773
			SET_STRING_ELT(tvec2, j, NA_STRING);
774
		} else
775
		    error("dataentry: internal memory problem");
776
	    }
777
	    SET_VECTOR_ELT(work2, i, tvec2);
778
	}
779
    }
780
 
781
    setAttrib(work2, R_NamesSymbol, names);    
782
    UNPROTECT(nprotect);
783
    return work2;
784
}
785
 
786
 
787
 
788
 
789
 
790
static char *get_col_name(int col)
791
{
792
    static char clab[25];
793
    if (col <= xmaxused) {
794
	/* don't use NA labels */
795
	SEXP tmp = STRING_ELT(names, col - 1);
796
	if(tmp != NA_STRING) return(CHAR(tmp));
797
    }
798
    sprintf(clab, "var%d", col);
799
    return clab;
800
}
801
 
802
 
803
static CellType get_col_type(int col)
804
{
805
    SEXP tmp;
806
    CellType res = UNKNOWNN;
807
 
808
    if (col <= xmaxused) {
809
	tmp = VECTOR_ELT(work, col - 1);
810
	if(TYPEOF(tmp) == REALSXP) res = NUMERIC;
811
	if(TYPEOF(tmp) == STRSXP) res = CHARACTER;
812
    }
813
    return res;
814
}
815
 
816
 
817
 
818
 
819
 
820
static pascal Boolean deItemComparison(
821
	ControlRef browser, DataBrowserItemID itemOneID, 
822
	DataBrowserItemID itemTwoID, DataBrowserPropertyID property)
823
{
824
	SInt16 compareResult = 0;
825
	char buf1[500], buf2[500];
826
	SEXP tmp;
827
        int row;
828
 
829
        row = max(itemOneID,itemTwoID);
830
     #define Compare(i1,i2,p) deItemComparison(browser,i1,i2,p)
25531 iacus 831
	 if(property>2000 & property<3000 & row>0 & row<=ymaxused){
832
            tmp = VECTOR_ELT(work, property-2000-1);
25390 iacus 833
            if (!isNull(tmp)) {
834
                strcpy(buf1," ");
835
                strcpy(buf2," ");
836
                if(LENGTH(tmp)>itemOneID-1)
837
                    printelt(tmp, itemOneID-1, buf1);
838
                 if(LENGTH(tmp)>itemTwoID-1)
839
                    printelt(tmp, itemTwoID-1, buf2);
840
 
25531 iacus 841
                if(get_col_type(property-2000) == CHARACTER)
25390 iacus 842
                        compareResult = strcmp(buf1,buf2);
843
                    else {
844
                        char *endp1,*endp2;
845
                        double new1 = R_strtod(buf1, &endp1);
846
                        double new2 = R_strtod(buf2, &endp2);
847
                        if(isBlankString(endp1) & isBlankString(endp2))
848
                            if(new1 < new2) compareResult = -1;
849
                            else if(new1>new2) compareResult = 1;
850
                         }
851
 
852
                if (compareResult < 0) return true;
853
			else if (compareResult > 0) return false;
854
			else return Compare(itemOneID, itemTwoID, '????');
855
                }
856
        }
857
 
858
 
859
        return itemOneID < itemTwoID;      
860
 
861
 
862
}
863
 
864
 
25522 iacus 865
struct WindowinfoStruct
866
{
867
	OSType			windowidentifier;
868
	CGContextRef		cgContext;
869
};
870
typedef struct WindowinfoStruct WindowinfoStruct;
25390 iacus 871
 
25531 iacus 872
DataBrowserItemID LastSelItem = 0;
873
DataBrowserPropertyID LastSelProp = 0;
25390 iacus 874
 
25522 iacus 875
static pascal void deCustomDrawProc( ControlRef browser, DataBrowserItemID item, DataBrowserPropertyID property, DataBrowserItemState itemState, const Rect *theRect, SInt16 gdDepth, Boolean colorDevice)
876
{
25531 iacus 877
        CFStringRef	text;
878
        RGBColor	fg = CurrentPrefs.FGOutputColor;
879
        RGBColor	bg = CurrentPrefs.BGOutputColor;        
880
	Str255 pascalString;
881
	SEXP tmp;
882
        int i,col,row=-1;
883
        char buf[1000];
884
 
885
 
886
       if(property>=2000 & property<10000){
887
          col = property-2000;
888
          row = item;
889
       }
25522 iacus 890
 
25531 iacus 891
       if(property==2000)
892
               text = CFStringCreateWithFormat( NULL, NULL, CFSTR("%d"), row );
893
 
894
//fprintf(stderr,"\n prop=%d, id=%d",property, item);
895
       if(property>2000 & row>0 & row<=ymaxused){          
896
          tmp = VECTOR_ELT(work, col-1);
897
          if (!isNull(tmp)) {
898
             strcpy(buf,"     ");
899
             if(LENGTH(tmp)>row-1)
900
              printelt(tmp, row-1, buf);
901
             } 
902
             CopyCStringToPascal(buf,pascalString);
903
             text = CFStringCreateWithPascalString(CFAllocatorGetDefault(), pascalString, kCFStringEncodingMacRoman);
904
        }   
905
//         fprintf(stderr,"\n it=%d, lastit=%d, pro=%d, lastpro=%d",item, LastSelItem, property, LastSelProp);
906
if( (property == LastSelProp) && (item == LastSelItem)){
907
//	if( (itemState == kDataBrowserItemIsSelected)  ){
908
           bg = CurrentPrefs.BGInputColor;
909
           fg = CurrentPrefs.FGInputColor;
910
	} 
25390 iacus 911
 
25531 iacus 912
        RGBForeColor( &bg );
913
        PaintRect( theRect );	//	First paint the hilite rect, then the text on top
25390 iacus 914
 
25531 iacus 915
        RGBForeColor( &fg );
916
	DrawThemeTextBox( text, kThemeApplicationFont, kThemeStateActive, true, theRect, teFlushRight, NULL );		
917
	if(text)
918
         CFRelease(text);
919
 
920
         if( (property == LastSelProp) && (item == LastSelItem))
921
          SetDataBrowserEditItem(browser,item,property);
922
 
923
  //     if(property!=1000)
924
  //       fprintf(stderr,"\nbuf=%s prop=%d, id=%d, top=%d, left=%d, bottom=%d, right=%d", buf, property, item, theRect->top, theRect->left, theRect->bottom, theRect->right);
25522 iacus 925
}
25390 iacus 926
 
927
 
928
 
25531 iacus 929
static pascal Boolean deCustomHitTestProc(ControlRef browser, DataBrowserItemID item, DataBrowserPropertyID property,
930
const Rect *theRect, const Rect *mouseRect){
25390 iacus 931
 
25531 iacus 932
if(!MouseClicked)
933
 return(false);
934
if(  (theRect->top <= mouseRect->top) && (theRect->left <= mouseRect->left) && (theRect->bottom >= mouseRect->bottom) && (theRect->right >=mouseRect->right)) {
935
 //fprintf(stderr,"\n (dentro) prop=%d item=%d, moouse=%d",property,item,MouseClicked);
936
 SetDataBrowserSelectedItems (browser,1,&item,kDataBrowserItemsAssign);
937
 LastSelItem = item;
938
 LastSelProp = property;
939
 MouseClicked = false;
940
 return(true);
941
 }
942
else
943
 return(false);
25390 iacus 944
 
25531 iacus 945
}
25390 iacus 946
 
947
 
25531 iacus 948
static pascal Boolean deCustomEditTextProc(ControlRef browser, DataBrowserItemID item,
949
DataBrowserPropertyID property, CFStringRef theString, Rect *maxEditTextRect, Boolean *shrinkToFit){
950
char buf[200];
25390 iacus 951
 
25531 iacus 952
 theString = CFStringCreateWithFormat( NULL, NULL, CFSTR("%s"), "ciao" );
953
//if( CFStringGetCString (theString, buf, 150,  kCFStringEncodingMacRoman) == noErr)
954
// fprintf(stderr,"\n string=%s",buf);
955
//else
956
fprintf(stderr,"\n no string"); 
25390 iacus 957
 
25531 iacus 958
return(true);
959
}
25390 iacus 960
 
961
 
962
 
963
 
964
#endif  /* HAVE_AQUA */
965
 
966
#endif /* __AQUA_DATA_ENTRY__ */
967
 
968
 
969