comparison anagram/vaclgui/dview.cpp @ 0:13d2b8934445

Import AnaGram (near-)release tree into Mercurial.
author David A. Holland
date Sat, 22 Dec 2007 17:52:45 -0500
parents
children
comparison
equal deleted inserted replaced
-1:000000000000 0:13d2b8934445
1 /*
2 * AnaGram, A System for Syntax Directed Programming
3 * Copyright 1997-2002 Parsifal Software. All Rights Reserved.
4 * See the file COPYING for license and usage terms.
5 *
6 * dview.cpp
7 */
8
9 #include <icoordsy.hpp>
10 #include <windows.h>
11 #include "port.h"
12
13 #include "agcstack.h"
14 #include "arrays.h"
15 #include "ctrlpanel.hpp"
16 #include "dview.hpp"
17 #include "dvplug.hpp"
18 #include "helpview.hpp"
19 #include "minmax.h"
20 #include "myalloc.h"
21 #include "vaclgui.hpp"
22
23 //#define INCLUDE_LOGGING
24 #include "log.h"
25
26
27 const int AgDataView::defaultWindowHeight = 12;
28
29 void logFont(IFont activeFont, char *p) {
30 LOGV(activeFont.name()) LV(activeFont.pointSize());
31 LOGV(activeFont.isBold()) LCV(activeFont.isItalic());
32 LOGV(activeFont.textWidth(p)) LCV(p);
33 }
34
35 void logFont(IFont activeFont) {
36 LOGV(activeFont.name()) LV(activeFont.pointSize());
37 LOGV(activeFont.isBold()) LCV(activeFont.isItalic());
38 }
39
40 AgDataView::AgDataView(IWindow *ownerWindow_, WindowData *windowData_)
41 : ICanvas(nextChildId(), ownerWindow_, ownerWindow_)
42 , ownerWindow(ownerWindow_)
43 , windowData(windowData_)
44 , horizontalScrollBar(nextChildId(), this, this, IRectangle(),
45 IScrollBar::horizontal | IWindow::visible)
46 , verticalScrollBar(nextChildId(), this, this, IRectangle(),
47 IScrollBar::vertical | IWindow::visible)
48 , dataArea(this)
49 , vsbShowing(false)
50 , hsbShowing(false)
51 , columnHeadTitle(nextChildId(), this)
52 , columnHeadsPresent(0)
53 , cursorLine(0)
54 , mouseDown(0)
55 , tabArray(0)
56 , popUpMenu(this, nextChildId())
57 , popUpInitialized(0)
58 , tableWidth(0)
59 , color(&ColorSpec::data)
60 , cursorColor(&ColorSpec::inactiveCursor)
61 , prevHorizontal(0)
62 , prevVertical(0)
63 //, rightButtonDown(0)
64 , rightButtonState(buttonIdle)
65 , layoutActive(0)
66 , dataColorChange(this, onColorChange)
67 , fontChange(this, onFontChange)
68 , enterAction(actionObject(messageBeep))
69 , verticalLineCount(0)
70 , layoutComplete(0)
71 , helpTopic(0)
72 {
73 windowId = id();
74 LOGSECTION("AgDataView::AgDataView");
75 LOGV(windowId);
76 LOGV((int) this);
77 setFont(FontSpec::dataTable);
78 dataArea.setFont(FontSpec::dataTable);
79 LOGV(dataArea.font().name());
80 columnHeadTitle.setFont(FontSpec::columnHead);
81 dataColorChange.attach(&ColorSpec::data);
82 dataColorChange.attach(&ColorSpec::inactiveCursor);
83 dataColorChange.attach(&ColorSpec::activeCursor);
84 fontChange.attach(&FontSpec::dataTable);
85 fontChange.attach(&FontSpec::columnHead);
86 fontChange.attach(&FontSpec::markedToken);
87
88 horizontalScrollBar.setScrollableRange(IRange(0,100));
89 horizontalScrollBar.moveScrollBoxTo(0);
90 verticalScrollBar.setScrollableRange(IRange(0,100));
91 verticalScrollBar.moveScrollBoxTo(0);
92 cursorLine = 0;
93
94 IWindow *f;
95 for (f = ownerWindow; !f->isFrameWindow(); f=f->parent());
96 frameWindow = (AgFrame *) f;
97 frameWindow->helpCursorSupported = 1;
98 LOGV(frameWindow->windowTitle.text());
99
100 ok_ptr(windowData);
101 AgString title = windowData->columnHeadTitle();
102 LOGV(title.pointer());
103 if (title.exists()) {
104 columnHeadTitle.setTitles(windowData->nColumns(), title);
105 columnHeadTitle.setMargin(avgCharWidth());
106 columnHeadTitle.enableFillBackground();
107 columnHeadTitle.show();
108 columnHeadsPresent = 1;
109 }
110
111
112 int nCols = windowData->nColumns();
113 tabArray = new int[nCols + 1];
114 memset(tabArray, 0, (nCols+1)*sizeof(int));
115 columnHeadTitle.setTabs(tabArray);
116 LOGV(tabArray[0]);
117 tableHeight = lineHeight()*windowData->nLines();
118 LOGV(windowData->nLines());
119 LOGV(tableHeight);
120
121 LOGV(auxMenu.exists());
122
123 ICommandHandler ::handleEventsFor(this);
124 IKeyboardHandler::handleEventsFor(this);
125 IMouseHandler ::handleEventsFor(&dataArea);
126 IMouseHandler ::handleEventsFor(&columnHeadTitle);
127 IMouseHandler ::handleEventsFor(&verticalScrollBar);
128 IMouseHandler ::handleEventsFor(&horizontalScrollBar);
129 IPaintHandler ::handleEventsFor(&dataArea);
130 IResizeHandler ::handleEventsFor(this);
131 IScrollHandler ::handleEventsFor(this);
132 AgHelpHandler ::handleEventsFor(frameWindow);
133 AgFocusHandler ::handleEventsFor(&dataArea);
134
135 ((AgDataViewPlug *)windowData)->connect(this);
136
137 auxMenu = windowData->auxMenu();
138 if (auxMenu.exists()) {
139 IMenuHandler::handleEventsFor(&dataArea);
140 }
141 LOGV(auxMenu.exists());
142 LOGS("menu handler attached");
143
144 initPopUp();
145
146 show();
147 windowData->synchCursor(cursorLine);
148 }
149
150 void AgDataView::disconnect() {
151 LOGSECTION("AgDataView::disconnect");
152 LOGV((int) frameWindow);
153 }
154
155
156 AgDataView &AgDataView::setColumnTitles(AgString title) {
157 LOGSECTION("AgDataView::setColumnTitles");
158 LOGV((int) frameWindow);
159 if (title.exists()) {
160 LOGV(title.pointer());
161 columnHeadTitle.setTitles(windowData->nColumns(), title);
162 columnHeadTitle.setMargin(avgCharWidth());
163 columnHeadTitle.enableFillBackground();
164 columnHeadsPresent = 1;
165 }
166 return *this;
167 }
168
169 Boolean AgDataView::gotFocus(IEvent &) {
170 LOGSECTION("AgDataView::gotFocus");
171 LOGV(windowId);
172 LOGV((int) this);
173 focusWindowId = windowId;
174 columnHeadTitle.color = &ColorSpec::activeTitle;
175 columnHeadTitle.refresh();
176 cursorColor = &ColorSpec::activeCursor;
177 if (windowData == 0) {
178 return true;
179 }
180 repaintLine(cursorLine);
181 windowData->synchCursor(cursorLine);
182 return false;
183 }
184
185 Boolean AgDataView::lostFocus(IEvent &) {
186 LOGSECTION("AgDataView::lostFocus");
187 LOGV(windowId);
188 LOGV((int) this) LCV((int) windowData);
189 columnHeadTitle.color = &ColorSpec::inactiveTitle;
190 columnHeadTitle.refresh();
191 cursorColor = &ColorSpec::inactiveCursor;
192 if (windowData == 0) {
193 return true;
194 }
195 ok_ptr(windowData);
196 repaintLine(cursorLine);
197 return false;
198 }
199
200
201 AgDataView &AgDataView::init(WindowData *windowData_) {
202 LOGSECTION("AgDataView::init");
203 LOGV(windowId);
204 LOGV((int) this);
205 horizontalScrollBar.setScrollableRange(IRange(0,100));
206 horizontalScrollBar.moveScrollBoxTo(0);
207 verticalScrollBar.setScrollableRange(IRange(0,100));
208 verticalScrollBar.moveScrollBoxTo(0);
209 cursorLine = 0;
210
211 ok_ptr(windowData_);
212 windowData = windowData_;
213 LOGV((int) frameWindow);
214 LOGV((int) windowData);
215 LOGV(windowId);
216 AgString title = windowData->columnHeadTitle();
217 if (title.exists()) {
218 LOGV(title.pointer());
219 columnHeadTitle.setTitles(windowData->nColumns(), title);
220 columnHeadTitle.setMargin(avgCharWidth());
221 columnHeadTitle.enableFillBackground();
222 columnHeadTitle.show();
223 columnHeadsPresent = 1;
224 }
225
226
227 if (tabArray == NULL) {
228 int nCols = windowData->nColumns();
229 tabArray = new int[nCols + 1];
230 memset(tabArray, 0, (nCols+1)*sizeof(int));
231 }
232 columnHeadTitle.setTabs(tabArray);
233 LOGV(tabArray[0]);
234 tableHeight = lineHeight()*windowData->nLines();
235 LOGV(windowData->nLines());
236 LOGV(tableHeight);
237 setLayoutDistorted(IWindow::layoutChanged,0);
238
239 ((AgDataViewPlug *)windowData)->connect(this);
240 auxMenu = windowData->auxMenu();
241 if (auxMenu.exists()) {
242 IMenuHandler::handleEventsFor(&dataArea);
243 LOGS("menu handler attached");
244 initPopUp();
245 }
246
247 windowData->synchCursor(cursorLine);
248 return *this;
249 }
250
251
252 AgDataView &AgDataView::reset() {
253 LOGSECTION("AgDataView::reset");
254 LOGV(windowId);
255 LOGV((int) this);
256 ok_ptr(windowData);
257 int nLines = windowData->nLines();
258 LOGV(nLines);
259 int newTableHeight = lineHeight()*nLines;
260 LOGV(windowData->nLines());
261 LOGV(tableHeight);
262 if (cursorLine >= nLines) {
263 cursorLine = nLines-1;
264 }
265 windowData->synchCursor(cursorLine);
266 //if (tableHeight != newTableHeight) {
267 tableHeight = newTableHeight;
268 doLayout();
269 refresh();
270 //}
271 LOGV(horizontalScrollBar.scrollBoxPosition());
272 LOGV(verticalScrollBar.scrollBoxPosition());
273 return *this;
274 }
275
276 AgDataView::AgDataView(IWindow *ownerWindow_)
277 : ICanvas(nextChildId(), ownerWindow_, ownerWindow_)
278 , ownerWindow(ownerWindow_)
279 , windowData(NULL)
280 , horizontalScrollBar(nextChildId(), this, this, IRectangle(),
281 IScrollBar::horizontal | IWindow::visible)
282 , verticalScrollBar(nextChildId(), this, this, IRectangle(),
283 IScrollBar::vertical | IWindow::visible)
284 , dataArea(this)
285 , vsbShowing(false)
286 , hsbShowing(false)
287 , columnHeadTitle(nextChildId(), this)
288 , columnHeadsPresent(0)
289 , cursorLine(0)
290 , mouseDown(0)
291 , tabArray(0)
292 , popUpMenu(this, nextChildId())
293 , popUpInitialized(0)
294 , tableWidth(0)
295 , color(&ColorSpec::data)
296 , cursorColor(&ColorSpec::inactiveCursor)
297 , prevHorizontal(0)
298 , prevVertical(0)
299 //, rightButtonDown(0)
300 , rightButtonState(buttonIdle)
301 , layoutActive(0)
302 , dataColorChange(this, onColorChange)
303 , fontChange(this, onFontChange)
304 , enterAction(actionObject(messageBeep))
305 , verticalLineCount(0)
306 , layoutComplete(0)
307 , helpTopic(0)
308 {
309 windowId = id();
310 LOGSECTION("AgDataView::AgDataView");
311 LOGV(windowId);
312 LOGV((int) this);
313 setFont(FontSpec::dataTable);
314 dataArea.setFont(FontSpec::dataTable);
315 LOGV(dataArea.font().name());
316 columnHeadTitle.setFont(FontSpec::columnHead);
317
318 dataColorChange.attach(&ColorSpec::data);
319 dataColorChange.attach(&ColorSpec::inactiveCursor);
320 dataColorChange.attach(&ColorSpec::activeCursor);
321 fontChange.attach(&FontSpec::dataTable);
322 fontChange.attach(&FontSpec::columnHead);
323 fontChange.attach(&FontSpec::markedToken);
324 IWindow *f;
325 for (f = ownerWindow; !f->isFrameWindow(); f=f->parent());
326 frameWindow = (AgFrame *) f;
327 frameWindow->helpCursorSupported = 1;
328 LOGV(frameWindow->windowTitle.text());
329 LOGV((int) frameWindow);
330 LOGV((int) this);
331
332 LOGV(id());
333
334 ICommandHandler ::handleEventsFor(this);
335 IKeyboardHandler::handleEventsFor(this);
336 if (auxMenu.exists()) {
337 IMenuHandler::handleEventsFor(&dataArea);
338 }
339 LOGV(auxMenu.exists());
340 LOGS("menu handler attached");
341 IMouseHandler ::handleEventsFor(&dataArea);
342 IMouseHandler ::handleEventsFor(&columnHeadTitle);
343 IMouseHandler ::handleEventsFor(&verticalScrollBar);
344 IMouseHandler ::handleEventsFor(&horizontalScrollBar);
345 IPaintHandler ::handleEventsFor(&dataArea);
346 IResizeHandler ::handleEventsFor(this);
347 IScrollHandler ::handleEventsFor(this);
348 AgHelpHandler ::handleEventsFor(frameWindow);
349 AgFocusHandler ::handleEventsFor(&dataArea);
350 show();
351 }
352
353 AgDataView::~AgDataView() {
354 LOGSECTION("AgDataView::~AgDataView");
355 LOGV(windowId) LCV((int) this) LCV((int) windowData);
356 ok_ptr(windowData);
357 delete [] tabArray;
358 //if (windowData == 0) return;
359 ICommandHandler ::stopHandlingEventsFor(this);
360 IKeyboardHandler::stopHandlingEventsFor(this);
361 if (auxMenu.exists()) {
362 IMenuHandler::stopHandlingEventsFor(&dataArea);
363 }
364 IMouseHandler ::stopHandlingEventsFor(&dataArea);
365 IMouseHandler ::stopHandlingEventsFor(&columnHeadTitle);
366 IMouseHandler ::stopHandlingEventsFor(&verticalScrollBar);
367 IMouseHandler ::stopHandlingEventsFor(&horizontalScrollBar);
368 IPaintHandler ::stopHandlingEventsFor(&dataArea);
369 IResizeHandler ::stopHandlingEventsFor(this);
370 IScrollHandler ::stopHandlingEventsFor(this);
371 AgHelpHandler ::stopHandlingEventsFor(frameWindow);
372 AgFocusHandler ::stopHandlingEventsFor(&dataArea);
373 ok_ptr(windowData);
374 delete windowData;
375 }
376
377 void AgDataView::onFontChange() {
378 LOGSECTION("AgDataView::onFontChange");
379 disableUpdate();
380 LOGS("dataTableFont");
381 logFont(FontSpec::dataTable);
382 setFont(FontSpec::dataTable);
383 dataArea.setFont(FontSpec::dataTable);
384 columnHeadTitle.setFont(FontSpec::columnHead);
385 LOGS("font()");
386 logFont(font());
387 logFont(dataArea.font());
388 tableWidth = 0;
389 doLayout();
390 enableUpdate();
391 show();
392 }
393
394 int AgDataView::findMaxWidth() {
395 LOGSECTION("AgDataView::findMaxWidth");
396 LOGV(windowId);
397 LOGV((int) this);
398 LOGV((int) frameWindow);
399
400 int maxWidth = 0;
401 ok_ptr(windowData);
402 int nLines = windowData->nLines();
403 int nCols = windowData->nColumns();
404 char *columnTitles = columnHeadTitle.title.pointer();
405 int i;
406
407 LOGV(nLines) LCV(nCols);
408 if (tabArray == NULL) {
409 tabArray = new int[nCols + 1];
410 }
411 memset(tabArray, 0, (nCols+1)*sizeof(int));
412 IFont windowFont = font();
413 LOGV(windowFont.name());
414 LOGV(windowFont.pointSize());
415
416 int lastColumnTitleWidth = 0;
417 //int *columnWidth = new int[nCols];
418 //int *columnWidth = local_array(nCols, int);
419 LocalArray<int> columnWidth(nCols);
420 memset(columnWidth, 0, nCols*sizeof(int));
421 LOGV(columnTitles);
422 if (columnTitles) {
423 //char *titles = new char[1+strlen(columnTitles)];
424 //char *titles = local_array(1+strlen(columnTitles), char);
425 LocalArray<char> titles(1+strlen(columnTitles));
426 strcpy(titles, columnTitles);
427 FindTabs tabs(titles);
428 char *p = tabs.getField();
429 i = 0;
430 while(i < nCols && p) {
431 int width = columnHeadTitle.font().textWidth(p);
432 columnWidth[i] = width;
433 LOGV(width) LCV(p);
434 lastColumnTitleWidth = width;
435 if (++i >= nCols) {
436 break;
437 }
438 p = tabs.getField();
439 }
440 while (i < nCols) {
441 tabArray[i++] = 0;
442 }
443 //delete [] titles;
444 }
445 else {
446 for (i = 0; i < nCols; i++) {
447 tabArray[i] = 0;
448 }
449 }
450 LOGV(tabArray[0]);
451 LOGV(columnWidth[0]);
452 //int *width = new int[nCols];
453 //int *width = local_array(nCols, int);
454 LocalArray<int> width(nCols);
455 int partialWidth = 0;
456
457 while (nLines--) {
458 //LOGSECTION("AgDataView::findMaxWidth line detail", Log::off);
459 LOGSECTION_OFF("AgDataView::findMaxWidth line detail");
460 AgString line = windowData->getLine(nLines);
461 LOGV(line.pointer());
462 FindTabs tabs(line.pointer());
463 char *p = tabs.getField();
464 LOGV(nLines);
465 LOGV(p);
466 i = 0;
467 while(i < nCols && p) {
468 width[i] = windowFont.textWidth(p);
469 LOGV(i) LCV(width[i]) LCV(p);
470 if (width[i] > columnWidth[i]) {
471 columnWidth[i] = width[i];
472 }
473 if (++i >= nCols) {
474 break;
475 }
476 p = tabs.getField();
477 }
478 LOGV(width[0]) LCV(line.pointer());
479 if (i < nCols) {
480 int w = 0;
481 while (i--) {
482 w += width[i];
483 }
484 if (w > partialWidth) {
485 partialWidth = w;
486 }
487 //continue;
488 }
489 }
490
491 //delete [] width;
492 for (i = 0; i < nCols; i++) {
493 columnWidth[i] += 2*avgCharWidth();
494 if (columnWidth[i] > tabArray[i]) {
495 tabArray[i] = columnWidth[i];
496 }
497 maxWidth += tabArray[i];
498 LOGV(tabArray[i]) LCV(maxWidth);
499 }
500 LOGV(tabArray[0]);
501 maxWidth += 2*avgCharWidth();
502 if (maxWidth < partialWidth) {
503 maxWidth = partialWidth;
504 }
505 //delete [] columnWidth;
506 columnHeadWidth = maxWidth - tabArray[nCols-1]
507 + lastColumnTitleWidth+2*avgCharWidth();
508 LOGV(columnHeadWidth);
509 return maxWidth;
510 }
511
512 AgDataView &AgDataView::adjustMaxWidth(AgString text) {
513 int nCols = windowData->nColumns();
514 int maxWidth = 0;
515 int margin = 2*avgCharWidth();
516 char *line = text.pointer();
517
518 LOGSECTION("AgDataView::adjustMaxWidth");
519 LOGV((int) frameWindow);
520 LOGV(line);
521 if (tableWidth == 0) {
522 tableWidth = findMaxWidth();
523 }
524 FindTabs tabs(line);
525 char *p = tabs.getField();
526
527 LOGV(p);
528
529 if (tabArray == NULL) {
530 tabArray = new int[nCols + 1];
531 memset(tabArray, 0, (nCols+1)*sizeof(int));
532 }
533 int i = 0;
534 while(i < nCols && p) {
535 int width = font().textWidth(p) + margin;
536 if (width > tabArray[i]) {
537 tabArray[i] = width;
538 }
539 LOGV(p) LCV(width);
540 if (++i >= nCols) {
541 break;
542 }
543 p = tabs.getField();
544 }
545 for (i = 0; i < nCols; i++) {
546 maxWidth += tabArray[i];
547 LOGV(tabArray[i]) LCV(maxWidth);
548 }
549 if (tableWidth < maxWidth) {
550 tableWidth = maxWidth;
551 }
552 LOGV(maxWidth);
553 LOGV(tabArray[0]);
554 return *this;
555 }
556
557 AgDataView &AgDataView::layout() {
558 LOGSECTION("AgDataView::layout");
559 LOGV(windowId);
560 LOGV((int) this);
561 LOGV((int) frameWindow);
562 if (layoutActive) {
563 return *this;
564 }
565 layoutActive++;
566 doLayout();
567 ICanvas::setLayoutDistorted(0, IWindow::layoutChanged);
568 ICanvas::layout();
569 layoutActive--;
570 return *this;
571 }
572
573 AgDataView &AgDataView::setLayoutDistorted(unsigned long i, unsigned long j) {
574 LOGSECTION("AgDataView::setLayoutDistorted");
575 LOGV((int) frameWindow);
576 LOGV(windowId);
577 LOGV((int) this);
578 LOGV(i) LCV(j);
579 LOGSTACK;
580
581 ICanvas::setLayoutDistorted(i, j);
582 return *this;
583 }
584
585 Boolean AgDataView::windowResize(IResizeEvent &event){
586 LOGSECTION("AgDataView::windowResize");
587 LOGV(windowId);
588 LOGV((int) this);
589 LOGV((int) frameWindow);
590
591 //if (event.controlWindow() != this) {
592 // return false;
593 //}
594
595 LOGV(id());
596
597 //setLayoutDistorted(IWindow::layoutChanged,0);
598 doLayout();
599 return false;
600 }
601
602 ISize AgDataView::calcMinimumSize() const {
603 int minWidth = 10*font().avgCharWidth();
604 int minHeight = 3*lineHeight();
605 if (columnHeadsPresent) {
606 minHeight += 2 + columnHeadTitle.minimumSize().height();
607 }
608 return ISize(minWidth, minHeight);
609 }
610
611 ISize AgDataView::suggestSize() {
612 LOGSECTION("AgDataView::suggestSize");
613 LOGV(windowId);
614 LOGV((int) this);
615 LOGV((int) frameWindow);
616
617 if (tableWidth == 0) {
618 tableWidth = findMaxWidth();
619 /*
620 int minWidth = 20*font().avgCharWidth();
621 int minHeight = 5*lineHeight();
622 if (columnHeadsPresent) {
623 minHeight += 2 + columnHeadTitle.minimumSize().height();
624 }
625 setMinimumSize(ISize(minWidth, minHeight));
626 */
627 }
628 int width = tableWidth;
629 int height = tableHeight;
630 ok_ptr(windowData);
631 LOGV(windowData->nLines());
632 LOGV(tableHeight);
633 LOGV(columnHeadsPresent);
634 LOGV(columnHeadTitle.minimumSize().height());
635 if (windowData->nLines() > defaultWindowHeight) {
636 width += verticalScrollBar.minimumSize().width() + 1;
637 height = lineHeight() * defaultWindowHeight;
638 }
639 else if (windowData->nLines() < 5) {
640 height = lineHeight() * 5;
641 }
642 if (columnHeadsPresent) {
643 height += 2 + columnHeadTitle.minimumSize().height();
644 }
645 LOGV(height);
646
647 LOGV(width) LCV(height);
648
649 return ISize(width, height);
650 }
651
652 ColorSpec *AgDataView::getLineColor(int k) {
653 if (k == cursorLine) {
654 return cursorColor;
655 }
656 return color;
657 }
658
659 char *findDelimiter(char *p, char c) {
660
661 // XXX: are we guaranteed that '\\' never occurs immediately before
662 // the end of a string, or do we just zoom off into the beyond when
663 // that happens?
664
665 while (*p && *p != c) {
666 if (*p == '\'') {
667 p++;
668 while (*p != '\'') {
669 if (*p++ == '\\') {
670 p++;
671 }
672 }
673 }
674 else if (*p == '"') {
675 p++;
676 while (*p != '"') {
677 if (*p++ == '\\') {
678 p++;
679 }
680 }
681 }
682 p++;
683 }
684 return p;
685 }
686
687 Boolean AgDataView::paintWindow(IPaintEvent &event) {
688 if (event.controlWindow() != &dataArea) {
689 return false;
690 }
691 if (windowData == 0) {
692 return false;
693 }
694 int nLines = windowData->nLines() - 1;
695 int height = lineHeight();
696 int leadingBias = 0;
697 IFont markFont(FontSpec::markedToken);
698
699 LOGSECTION("AgDataView::paintWindow");
700 LOGV(tabArray[0]);
701 LOGV(windowId);
702 LOGV((int) this);
703 IPresSpaceHandle presSpaceHandle = event.presSpaceHandle();
704
705 font().beginUsingFont(presSpaceHandle);
706 LOGV(font().name()) LCV(font().pointSize());
707 leadingBias = font().maxAscender() - markFont.maxAscender();
708 SetBkMode(presSpaceHandle, TRANSPARENT);
709 LOGV((int) frameWindow);
710
711 LOGV(nLines);
712 IRectangle invalidRect(
713 ICoordinateSystem::isConversionNeeded()
714 ? ICoordinateSystem::convertToApplication(event.rect(),dataArea.size())
715 : event.rect()
716 );
717
718 LOGV(invalidRect.asString());
719 LOGV(dataArea.size().asString());
720
721 int baseLine = verticalScrollBar.scrollBoxPosition();
722 int firstLine = baseLine + invalidRect.minY()/height;
723 int lastLine = baseLine + (invalidRect.maxY()+height - 1)/height - 1;
724
725 LOGV(horizontalScrollBar.scrollBoxPosition());
726 LOGV(verticalScrollBar.scrollBoxPosition());
727 LOGV(baseLine);
728 LOGV(firstLine);
729 LOGV(lastLine);
730
731 int yBias =
732 ICoordinateSystem::isConversionNeeded()
733 ? height - maxDescender()
734 : 0;
735
736 int xMargin = avgCharWidth();
737
738
739 LOGV(yBias);
740
741 int whereX = -horizontalScrollBar.scrollBoxPosition();
742 int whereY = (firstLine - baseLine)*height; //baseline location
743
744 LOGV(baseLine);
745 LOGV(firstLine);
746 LOGV(lastLine);
747 LOGV(horizontalScrollBar.scrollBoxPosition());
748
749 int lastInvalidLine = lastLine;
750 if (lastLine > nLines) {
751 lastLine = nLines;
752 }
753 int windowHeight = dataArea.rect().size().height();
754 int dataAreaWidth = dataArea.rect().size().width() - whereX;
755 ISize lineSize(dataAreaWidth, height);
756 IPoint offset(xMargin, 0);
757 int k;
758
759 LOGV(firstLine);
760 LOGV(lastLine);
761 for (k = firstLine; k >= 0 && k <= lastLine; k++, whereY += height) {
762 LOGSECTION("AgDataView::paintWindow line loop");
763 IPoint trueWhere(whereX, whereY + yBias);
764 IPoint where =
765 ICoordinateSystem::isConversionNeeded()
766 ? ICoordinateSystem::convertToNative(trueWhere, dataArea.size())
767 : trueWhere;
768 IRectangle trueLineRect(0, whereY, dataAreaWidth, whereY+height);
769 IRectangle lineRect =
770 ICoordinateSystem::isConversionNeeded()
771 ? ICoordinateSystem::convertToNative(trueLineRect, dataArea.size())
772 : trueLineRect;
773 ColorSpec *lineColor = getLineColor(k);
774 IColor bgndColor = lineColor->bg();
775 IColor fgndColor = lineColor->fg();
776
777 LOGV(lineRect.asString());
778 LOGV(where.asString());
779 event.clearBackground(lineRect,bgndColor);
780
781 AgString line = windowData->getLine(k);
782 char *p = line.pointer();
783 LOGV((int)p);
784 LOGV(p);
785 while (*p && *p != '<') {
786 p++;
787 }
788 if (*p == '<') {
789 while (*p && *p != '>') {
790 p++;
791 }
792 }
793 int bracketFlag = *p == '>';
794
795 LOGV(line.pointer());
796 FindTabs tabs(line.pointer());
797 p = tabs.getField();
798 int nCols = windowData->nColumns();
799 where += offset;
800 int i = 0;
801 char *star = 0;
802 IPoint starWhere = where;
803 if (*p == '*') {
804 *p = ' ';
805 star = p;
806 }
807 while (i < nCols && p) {
808 LOGV(p - line.pointer());
809 LOGV(p);
810 IPoint drawPoint(where);
811 int j = 0;
812 while (p[j] && p[j] == ' ') {
813 j++;
814 }
815 int flag = bracketFlag && p[j] == 'R' && p[j+7] == '<' && p[j+8] != '<';
816 if (!flag) {
817 char *q = p;
818 while (*q && strncmp(q, ", <", 3) != 0) {
819 q++;
820 }
821 //LOGV(q);
822 if (*q == ',') {
823 q += 2;
824 *q = 0;
825 logFont(font(), p);
826 //LOGV(drawPoint.asString());
827 event.drawText(p, drawPoint, fgndColor);
828 drawPoint += IPair(font().textWidth(p), 0);
829 //drawPoint += IPair(gcFont.textWidth(p), 0);
830 //LOGV(font().textWidth(p)) LCV(p);
831 //LOGV(drawPoint.asString());
832 p = q;
833 *p = '<';
834 }
835 }
836 else {
837 p[j+7] = 0;
838 logFont(font(), p);
839 //LOGV(drawPoint.asString());
840 event.drawText(p, drawPoint, fgndColor);
841 drawPoint += IPair(font().textWidth(p), 0);
842 //LOGV(font().textWidth(p)) LCV(p);
843 //LOGV(drawPoint.asString());
844 p += j+7;
845 *p = '<';
846 }
847 //LOGV(flag);
848 //LOGV(p);
849 if (bracketFlag && *p == '<' && p[1] != '<') {
850 p += 2;
851 IFont markFont(FontSpec::markedToken);
852 char *q = p;
853 q = findDelimiter(q, '>');
854 if (q) {
855 *q = 0;
856 }
857 //LOGV(p);
858 //LOGV(font().textWidth(p));
859 //LOGV(markFont.name()) LCV(markFont.pointSize());
860 //LOGV(markFont.textWidth(p));
861 logFont(font(), p);
862 //LOGV(drawPoint.asString());
863 int saveY = drawPoint.y();
864 drawPoint.setY(saveY +leadingBias);
865 //LOGV(drawPoint.asString());
866 markFont.beginUsingFont(presSpaceHandle);
867 logFont(font(), p);
868 event.drawText(p, drawPoint, fgndColor);
869 drawPoint.setY(saveY);
870 drawPoint += IPair(markFont.textWidth(p), 0);
871 //LOGV(font().textWidth(p)) LCV(p);
872 //LOGV(drawPoint.asString());
873 markFont.endUsingFont(presSpaceHandle);
874 p = q+1;
875 //LOGS("emphasis complete");
876 }
877 logFont(font(), p);
878 LOGV(drawPoint.asString());
879 event.drawText(p,drawPoint, fgndColor);
880 where += IPoint(tabArray[i], 0);
881 LOGV(font().textWidth(p)) LCV(p);
882 LOGV(tabArray[i]);
883 LOGV(where);
884 if (++i >= nCols) {
885 break;
886 }
887 p = tabs.getField();
888 }
889 if (star) {
890 event.drawText("*", starWhere, fgndColor);
891 }
892 }
893 if (k <= lastInvalidLine) {
894 IRectangle trueRemainder(0,whereY,dataAreaWidth, windowHeight);
895 IRectangle remainder =
896 ICoordinateSystem::isConversionNeeded()
897 ? ICoordinateSystem::convertToNative(trueRemainder, dataArea.size())
898 : trueRemainder;
899 //LOGV(remainder.asString());
900 event.clearBackground(remainder,color->bg());
901 }
902
903 font().endUsingFont(presSpaceHandle);
904 return true;
905 }
906
907 AgDataView &AgDataView::repaintLine(int line) {
908 if (windowData == 0) {
909 return *this;
910 }
911 if (line < 0 || line >= windowData->nLines()) {
912 return *this;
913 }
914 int topLine = verticalScrollBar.scrollBoxPosition();
915 int y = (line - topLine)*lineHeight();
916 LOGSECTION("AgDataView::repaintLine");
917 LOGV(windowId);
918 LOGV((int) this);
919 LOGV((int) frameWindow);
920 LOGV(horizontalScrollBar.scrollBoxPosition());
921 LOGV(verticalScrollBar.scrollBoxPosition());
922 LOGV(line);
923 LOGV(cursorLine);
924 IRectangle rect(0,y,dataArea.rect().size().width(), y + lineHeight());
925 LOGV(rect.asString());
926 //dataArea.refresh(rect, true);
927 dataArea.refresh(rect);
928 return *this;
929 }
930
931 AgDataView &AgDataView::copyTo(IClipboard &clipboard) {
932 int i;
933 int nLines = windowData->nLines();
934 AgCharStack charStack;
935 if (copyTitle.exists()) {
936 //charStack.push(copyTitle).push("\r\n\r\n");
937 charStack << copyTitle << "\r\n\r\n";
938 }
939 //charStack.push(windowData->columnHeadTitle());
940 charStack << windowData->columnHeadTitle();
941 charStack.push("\r\n");
942 for (i = 0; i < nLines; i++) {
943 //charStack.push(windowData->getLine(i));
944 charStack << windowData->getLine(i);
945 charStack.push("\r\n");
946 }
947 clipboard.setText(charStack.popString().pointer());
948 return *this;
949 }
950
951 AgDataView &AgDataView::repositionWindow() {
952 LOGSECTION("AgDataView::repositionWindow");
953 LOGV(windowId);
954 LOGV((int) this);
955 int horizontalOffset = horizontalScrollBar.scrollBoxPosition()
956 - prevHorizontal;
957 int verticalOffset = verticalScrollBar.scrollBoxPosition()
958 - prevVertical;
959
960 IPoint displacement(-horizontalOffset, -lineHeight()*verticalOffset);
961
962 LOGV(displacement.asString());
963
964 int oldCursor = cursorLine;
965 int line = verticalScrollBar.scrollBoxPosition();
966 if (cursorLine < line) {
967 cursorLine = line;
968 }
969 else {
970 LOGV(windowData->nLines());
971 LOGV(verticalScrollBar.scrollableRange().asString());
972 LOGV(verticalScrollBar.visibleCount());
973 //line += verticalScrollBar.visibleCount() - 1;
974 line += verticalLineCount - 1;
975 if (line < 0) {
976 line = 0;
977 }
978 if (cursorLine > line) {
979 cursorLine = line;
980 }
981 }
982 if (columnHeadsPresent) {
983 int pos = horizontalScrollBar.scrollBoxPosition();
984 if (pos != columnHeadTitle.xPos) {
985 columnHeadTitle.xPos = pos;
986 columnHeadTitle.refresh();
987 }
988 }
989 LOGV(cursorLine);
990 dataArea.scrollWindow(displacement);
991 dataArea.refresh();
992 prevHorizontal = horizontalScrollBar.scrollBoxPosition();
993 prevVertical = verticalScrollBar.scrollBoxPosition();
994 if (cursorLine != oldCursor) {
995 repaintLine(oldCursor);
996 repaintLine(cursorLine);
997 windowData->synchCursor(cursorLine);
998 selectAction.performDeferred();
999 }
1000
1001 return *this;
1002 }
1003
1004 Boolean AgDataView::findNext(AgString s) {
1005 LOGSECTION("AgDataView::findNext");
1006 LOGV(s);
1007 searchProcess.setKey(s);
1008 int ln = cursorLine + 1;
1009 while (ln < windowData->nLines()) {
1010 AgString line = windowData->getLine(ln);
1011 LOGV(line);
1012 char *p = searchProcess.scanForward(line.pointer(), line.size());
1013 if (p) {
1014 LOGV(ln) LCV(line);
1015 setCursorLine(ln).synchCursor(ln);
1016 return true;
1017 }
1018 ln++;
1019 }
1020 return false;
1021 }
1022
1023 Boolean AgDataView::findPrev(AgString s) {
1024 searchProcess.setKey(s);
1025 int ln = cursorLine - 1;
1026 while (ln >= 0) {
1027 AgString line = windowData->getLine(ln);
1028 char *p = searchProcess.scanReverse(line.pointer(), line.size());
1029 if (p) {
1030 setCursorLine(ln).synchCursor(ln);
1031 return true;
1032 }
1033 ln--;
1034 }
1035 return false;
1036 }
1037
1038
1039 AgDataView &AgDataView::setCursorLine(int ln) {
1040 LOGSECTION("AgDataView::setCursorLine");
1041 LOGV(ln);
1042 LOGV(windowId);
1043 LOGV(frameWindow->windowTitle.text());
1044 LOGV((int) this);
1045 LOGV((int) frameWindow);
1046 LOGV(layoutComplete);
1047
1048 int lastLine = windowData->nLines() - 1;
1049 if (ln > lastLine) {
1050 ln = lastLine;
1051 }
1052 if (ln < 0) {
1053 ln = 0;
1054 }
1055 int oldLine = cursorLine;
1056 LOGV(windowData->nLines());
1057 LOGV(verticalScrollBar.scrollableRange().asString());
1058 LOGV(verticalScrollBar.visibleCount());
1059 //int count = verticalScrollBar.visibleCount();
1060 int count = verticalLineCount;
1061 cursorLine = ln;
1062 if (!layoutComplete) {
1063 return *this;
1064 }
1065
1066 LOGV(oldLine);
1067 LOGV(cursorLine);
1068 LOGV(count);
1069
1070 int firstLine = verticalScrollBar.scrollBoxPosition();
1071 lastLine = firstLine + count - 1;
1072
1073 LOGV(firstLine);
1074 LOGV(lastLine);
1075 int repositionFlag = 0;
1076 if (cursorLine < firstLine) {
1077 firstLine = cursorLine;
1078 verticalScrollBar.moveScrollBoxTo(firstLine);
1079 repositionFlag = 1;
1080 }
1081 if (cursorLine > lastLine) {
1082 firstLine = cursorLine - (count - 1);
1083 if (firstLine < 0) {
1084 firstLine = 0;
1085 }
1086 verticalScrollBar.moveScrollBoxTo(firstLine);
1087 repositionFlag = 1;
1088 }
1089 if (repositionFlag) {
1090 repositionWindow();
1091 }
1092 if (cursorLine == oldLine) {
1093 return *this;
1094 }
1095 //windowData->synchCursor(cursorLine);
1096 repaintLine(oldLine);
1097 repaintLine(cursorLine);
1098 LOGV(firstLine);
1099 return *this;
1100 }
1101
1102 AgDataView &AgDataView::synchCursor(int ln) {
1103 windowData->synchCursor(ln);
1104 return *this;
1105 }
1106
1107 /*
1108 *
1109 * Layout considerations:
1110 *
1111 * The data view consists of up to four parts: two scroll bars, a heading
1112 * and a data area.
1113 *
1114 * The presence or absence of the scroll bars depends on the relative size
1115 * of the data area and the size of the table to be displayed.
1116 */
1117
1118 AgDataView &AgDataView::doLayout() {
1119 LOGSECTION("AgDataView::doLayout");
1120 LOGV((int) frameWindow);
1121 LOGV(id());
1122
1123 LOGV(windowId);
1124 LOGV((int) this);
1125 LOGV(font().name());
1126 LOGV(font().pointSize());
1127 ISize canvasSize = size();
1128 int canvasWidth = canvasSize.width();
1129 int canvasHeight = canvasSize.height();
1130 if (canvasHeight == 0) {
1131 return *this;
1132 }
1133 //if (tableWidth == 0) tableWidth = findMaxWidth();
1134 tableWidth = findMaxWidth();
1135 tableHeight = lineHeight()*windowData->nLines();
1136
1137 LOGV(canvasWidth);
1138 LOGV(canvasHeight);
1139
1140 int dataWidth = canvasWidth;
1141 int dataHeight = canvasHeight;
1142 int dataY = 0;
1143 ISize columnHeadSize = columnHeadTitle.minimumSize();
1144 if (columnHeadsPresent) {
1145 dataY = columnHeadSize.height() + 2;
1146 columnHeadSize.setHeight(dataY);
1147 dataHeight -= dataY;
1148 columnHeadTitle.moveTo(IPoint(0, 0));
1149 }
1150
1151 LOGV(dataWidth);
1152 LOGV(dataHeight);
1153
1154
1155 int vsbWidth = verticalScrollBar.minimumSize().width();
1156 int hsbHeight = horizontalScrollBar.minimumSize().height();
1157
1158 int horizontalPosition = horizontalScrollBar.scrollBoxPosition();
1159 int verticalPosition = verticalScrollBar.scrollBoxPosition();
1160
1161 Boolean vsb = true;
1162 Boolean hsb = true;
1163
1164 if (tableHeight > dataHeight
1165 && tableWidth <= canvasWidth - vsbWidth - 1) {
1166 // vertical scroll bar only
1167 vsb = true;
1168 hsb = false;
1169 }
1170 else if (tableWidth > canvasWidth
1171 && tableHeight <= dataHeight - hsbHeight - 1) {
1172 // horizontal scroll bar only
1173 vsb = false;
1174 hsb = true;
1175 }
1176 else if (tableWidth <= canvasWidth && tableHeight <= dataHeight) {
1177 // no scroll bars
1178 vsb = hsb = false;
1179 }
1180
1181 if (vsb && !vsbShowing) {
1182 verticalScrollBar.moveScrollBoxTo(0);
1183 prevVertical = 0;
1184 verticalScrollBar.show();
1185 vsbShowing = true;
1186 }
1187 if (!vsb && vsbShowing) {
1188 verticalScrollBar.hide();
1189 vsbShowing = false;
1190 verticalScrollBar.moveScrollBoxTo(0);
1191 prevVertical = 0;
1192 }
1193
1194 if (hsb && !hsbShowing) {
1195 horizontalScrollBar.show();
1196 hsbShowing = true;
1197 horizontalScrollBar.moveScrollBoxTo(0);
1198 prevHorizontal = 0;
1199 }
1200 if (!hsb && hsbShowing) {
1201 horizontalScrollBar.hide();
1202 hsbShowing = false;
1203 horizontalScrollBar.moveScrollBoxTo(0);
1204 prevHorizontal = 0;
1205 }
1206
1207 if (vsbShowing) {
1208 dataWidth -= vsbWidth + 1;
1209 verticalScrollBar.moveTo(IPoint(dataWidth+1, 0));
1210 verticalScrollBar.sizeTo(ISize(vsbWidth, canvasHeight));
1211 }
1212
1213 if (hsbShowing) {
1214 dataHeight -= hsbHeight + 1;
1215 horizontalScrollBar.moveTo(IPoint(0, canvasHeight - hsbHeight));
1216 horizontalScrollBar.sizeTo(ISize(dataWidth, hsbHeight));
1217 }
1218
1219 dataArea.sizeTo(ISize(dataWidth, dataHeight));
1220 dataArea.moveTo(IPoint(0, dataY));
1221
1222
1223 LOGV(dataArea.size().asString());
1224 LOGV(dataArea.parentSize().asString());
1225
1226 LOGV(rect().asString());
1227 LOGV(dataArea.rect().asString());
1228 LOGV(horizontalScrollBar.rect().asString());
1229 LOGV(verticalScrollBar.rect().asString());
1230
1231 //int widthUnit = charWidth();
1232
1233 horizontalScrollBar.setScrollableRange(IRange(0,tableWidth-1));
1234 horizontalScrollBar.setVisibleCount(dataWidth);
1235 LOGV(horizontalScrollBar.scrollableRange().asString()) LCV(tableWidth);
1236 LOGV(horizontalScrollBar.visibleCount()) LCV(dataWidth);
1237
1238
1239 verticalScrollBar.setScrollableRange(IRange(0, windowData->nLines() - 1));
1240 verticalLineCount = dataHeight/lineHeight();
1241 //verticalScrollBar.setVisibleCount(dataHeight/lineHeight());
1242 verticalScrollBar.setVisibleCount(verticalLineCount);
1243 LOGV(dataHeight/lineHeight());
1244 LOGV(windowData->nLines());
1245 LOGV(verticalScrollBar.scrollableRange().asString());
1246 LOGV(verticalScrollBar.visibleCount());
1247 LOGV(verticalLineCount);
1248 horizontalPosition = min(
1249 (int) horizontalScrollBar.scrollBoxRange().upperBound(),
1250 horizontalPosition
1251 );
1252 verticalPosition = min(
1253 (int) verticalScrollBar.scrollBoxRange().upperBound(),
1254 verticalPosition
1255 );
1256
1257 horizontalScrollBar.setMinScrollIncrement(charWidth());
1258 verticalScrollBar.setMinScrollIncrement(1);
1259
1260 prevHorizontal = horizontalScrollBar.scrollBoxPosition();
1261 horizontalScrollBar.moveScrollBoxTo(horizontalPosition);
1262
1263 prevVertical = verticalScrollBar.scrollBoxPosition();
1264 verticalScrollBar.moveScrollBoxTo(verticalPosition);
1265
1266 LOGV(prevHorizontal);
1267 LOGV(prevVertical);
1268 LOGV(horizontalPosition);
1269 LOGV(verticalPosition);
1270 LOGV(horizontalScrollBar.scrollBoxPosition());
1271 LOGV(verticalScrollBar.scrollBoxPosition());
1272 LOGV(verticalPosition);
1273
1274 if (columnHeadsPresent) {
1275 columnHeadSize.setWidth(dataWidth);
1276 columnHeadTitle.sizeTo(columnHeadSize);
1277 columnHeadTitle.xPos = horizontalPosition;
1278 columnHeadTitle.refresh();
1279 }
1280 layoutComplete = 1;
1281 setCursorLine(cursorLine).synchCursor(cursorLine);
1282 return *this;
1283 }
1284
1285 Boolean AgDataView::lineDown(IScrollEvent &event) {
1286 if (event.scrollBarWindow() != &verticalScrollBar) {
1287 return false;
1288 }
1289 LOGSECTION("AgDataView::lineDown");
1290 moveScrollBox(event);
1291 repositionWindow();
1292 return true;
1293 }
1294
1295 Boolean AgDataView::lineLeft(IScrollEvent &event) {
1296 if (event.scrollBarWindow() != &horizontalScrollBar) {
1297 return false;
1298 }
1299 LOGSECTION("AgDataView::lineLeft");
1300 moveScrollBox(event);
1301 repositionWindow();
1302 return true;
1303 }
1304
1305 Boolean AgDataView::lineRight(IScrollEvent &event) {
1306 if (event.scrollBarWindow() != &horizontalScrollBar) {
1307 return false;
1308 }
1309 LOGSECTION("AgDataView::lineRight");
1310 LOGV(horizontalScrollBar.scrollBoxPosition());
1311 moveScrollBox(event);
1312 repositionWindow();
1313 LOGV(horizontalScrollBar.scrollBoxPosition());
1314 return true;
1315 }
1316
1317 Boolean AgDataView::lineUp(IScrollEvent &event) {
1318 if (event.scrollBarWindow() != &verticalScrollBar) {
1319 return false;
1320 }
1321 LOGSECTION("AgDataView::lineUp");
1322 moveScrollBox(event);
1323 repositionWindow();
1324 return true;
1325 }
1326
1327 Boolean AgDataView::pageDown(IScrollEvent &event) {
1328 if (event.scrollBarWindow() != &verticalScrollBar) {
1329 return false;
1330 }
1331 LOGSECTION("AgDataView::pageDown");
1332 moveScrollBox(event);
1333 repositionWindow();
1334 return true;
1335 }
1336
1337 Boolean AgDataView::pageLeft(IScrollEvent &event) {
1338 if (event.scrollBarWindow() != &horizontalScrollBar) {
1339 return false;
1340 }
1341 LOGSECTION("AgDataView::pageLeft");
1342 moveScrollBox(event);
1343 repositionWindow();
1344 return true;
1345 }
1346
1347 Boolean AgDataView::pageRight(IScrollEvent &event) {
1348 if (event.scrollBarWindow() != &horizontalScrollBar) {
1349 return false;
1350 }
1351 LOGSECTION("AgDataView::pageRight");
1352 moveScrollBox(event);
1353 repositionWindow();
1354 return true;
1355 }
1356
1357 Boolean AgDataView::pageUp(IScrollEvent &event) {
1358 if (event.scrollBarWindow() != &verticalScrollBar) {
1359 return false;
1360 }
1361 LOGSECTION("AgDataView::pageUp");
1362 moveScrollBox(event);
1363 repositionWindow();
1364 return true;
1365 }
1366
1367 Boolean AgDataView::scrollBoxTrack(IScrollEvent &event) {
1368 LOGSECTION("AgDataView::scrollBoxTrack");
1369 LOGV(verticalScrollBar.scrollBoxPosition());
1370 LOGV(horizontalScrollBar.scrollBoxPosition());
1371 moveScrollBox(event);
1372 //if (!event.controlWindow()->hasPointerCaptured()) {
1373 // event.controlWindow()->capturePointer(true);
1374 //}
1375 LOGV(verticalScrollBar.scrollBoxPosition());
1376 LOGV(horizontalScrollBar.scrollBoxPosition());
1377 repositionWindow();
1378 return true;
1379 }
1380
1381 Boolean AgDataView::scrollBoxTrackEnd(IScrollEvent &event) {
1382 //event.controlWindow()->releasePointer();
1383 moveScrollBox(event);
1384 repositionWindow();
1385 return true;
1386 }
1387
1388 Boolean AgDataView::key(IKeyboardEvent &event) {
1389 return false;
1390 }
1391
1392
1393 Boolean AgDataView::virtualKeyPress(IKeyboardEvent &event) {
1394 LOGSECTION("AgDataView::virtualKeyPress");
1395 LOGV((int) frameWindow);
1396 LOGV((int) event.virtualKey());
1397 LOGV(event.isShiftDown()) LCV(event.isCtrlDown()) LCV(event.isAltDown());
1398 switch (event.virtualKey()) {
1399 case IKeyboardEvent::newLine:
1400 case IKeyboardEvent::enter: {
1401 LOGSECTION("AgDataView::enter");
1402 if (enterAction.exists()) {
1403 enterAction.performDeferred();
1404 }
1405 return true;
1406 }
1407 case IKeyboardEvent::up: {
1408 int line = cursorLine;
1409 if (cursorLine > 0) {
1410 cursorLine--;
1411 }
1412 else {
1413 messageBeep();
1414 }
1415 if (line != cursorLine) {
1416 windowData->synchCursor(cursorLine);
1417 selectAction.performDeferred();
1418 }
1419 LOGV(cursorLine);
1420 if (cursorLine < verticalScrollBar.scrollBoxPosition()) {
1421 repaintLine(line);
1422 verticalScrollBar.moveScrollBoxTo(cursorLine);
1423 repositionWindow();
1424 return true;
1425 }
1426 repaintLine(line);
1427 repaintLine(cursorLine);
1428 return true;
1429 }
1430 case IKeyboardEvent::down: {
1431 LOGSECTION("Cursor down one line");
1432 int line = cursorLine;
1433 if (cursorLine < windowData->nLines() - 1) {
1434 cursorLine++;
1435 }
1436 else {
1437 messageBeep();
1438 }
1439 if (line != cursorLine) {
1440 selectAction.performDeferred();
1441 windowData->synchCursor(cursorLine);
1442 }
1443 LOGV(line) LCV(cursorLine);
1444 LOGV((int) this);
1445 LOGV((int) &cursorLine);
1446 LOGV(cursorLine);
1447 int bottomLine = verticalScrollBar.scrollBoxPosition()
1448 + verticalLineCount - 1;
1449 //+ verticalScrollBar.visibleCount() - 1;
1450
1451 LOGV(line);
1452 LOGV(cursorLine);
1453 LOGV(bottomLine);
1454
1455 if (cursorLine > bottomLine) {
1456 LOGS("scrolling");
1457 verticalScrollBar.moveScrollBoxTo(
1458 cursorLine
1459 - verticalLineCount + 1
1460 //- verticalScrollBar.visibleCount() + 1
1461 );
1462 repositionWindow();
1463 }
1464 repaintLine(line);
1465 repaintLine(cursorLine);
1466 return true;
1467 }
1468 case IKeyboardEvent::pageUp: {
1469 int line = cursorLine;
1470 if (cursorLine == 0) {
1471 messageBeep();
1472 return true;
1473 }
1474 //cursorLine -= verticalScrollBar.visibleCount();
1475 cursorLine -= verticalLineCount;
1476 if (cursorLine < 0 || event.isCtrlDown()) {
1477 cursorLine = 0;
1478 repaintLine(line);
1479 repaintLine(cursorLine);
1480 }
1481 if (cursorLine < verticalScrollBar.scrollBoxPosition()) {
1482 verticalScrollBar.moveScrollBoxTo(cursorLine);
1483 repositionWindow();
1484 }
1485 if (line != cursorLine) {
1486 windowData->synchCursor(cursorLine);
1487 selectAction.performDeferred();
1488 }
1489 return true;
1490 }
1491 case IKeyboardEvent::home: {
1492 if (cursorLine && event.isCtrlDown()) {
1493 int line = cursorLine;
1494 cursorLine = 0;
1495 windowData->synchCursor(cursorLine);
1496 selectAction.performDeferred();
1497 if (cursorLine < verticalScrollBar.scrollBoxPosition()) {
1498 repaintLine(line);
1499 verticalScrollBar.moveScrollBoxTo(cursorLine);
1500 repositionWindow();
1501 return true;
1502 }
1503 repaintLine(line);
1504 repaintLine(cursorLine);
1505 return true;
1506 }
1507 else {
1508 messageBeep();
1509 }
1510 return true;
1511 }
1512 case IKeyboardEvent::end: {
1513 int lastLine = windowData->nLines() - 1;
1514 if (cursorLine < lastLine && event.isCtrlDown()) {
1515 int line = cursorLine;
1516 cursorLine = lastLine;
1517 windowData->synchCursor(cursorLine);
1518 selectAction.performDeferred();
1519 if (cursorLine <
1520 verticalScrollBar.scrollBoxPosition()-verticalLineCount) {
1521 repaintLine(line);
1522 verticalScrollBar.moveScrollBoxTo(cursorLine);
1523 repositionWindow();
1524 return true;
1525 }
1526 repaintLine(line);
1527 repaintLine(cursorLine);
1528 return true;
1529 }
1530 else {
1531 messageBeep();
1532 }
1533 return true;
1534 }
1535 case IKeyboardEvent::pageDown: {
1536 int line = cursorLine;
1537 cursorLine += verticalLineCount;
1538 int lastLine = windowData->nLines() - 1;
1539 if (cursorLine == lastLine) {
1540 messageBeep();
1541 return true;
1542 }
1543 if (cursorLine > lastLine || event.isCtrlDown()) {
1544 cursorLine = lastLine;
1545 repaintLine(line);
1546 repaintLine(cursorLine);
1547 }
1548 if (cursorLine > verticalScrollBar.scrollBoxPosition()) {
1549 verticalScrollBar.moveScrollBoxTo(
1550 cursorLine - verticalLineCount + 1
1551 );
1552 repositionWindow();
1553 }
1554 if (line != cursorLine) {
1555 windowData->synchCursor(cursorLine);
1556 selectAction.performDeferred();
1557 }
1558 return true;
1559 }
1560 case IKeyboardEvent::left: {
1561 int position = horizontalScrollBar.scrollBoxPosition() - charWidth();
1562 if (position >= 0) {
1563 horizontalScrollBar.moveScrollBoxTo(position);
1564 repositionWindow();
1565 }
1566 else {
1567 messageBeep();
1568 }
1569 return true;
1570 }
1571 case IKeyboardEvent::right: {
1572 int position = horizontalScrollBar.scrollBoxPosition() + charWidth();
1573 if (position <= horizontalScrollBar.scrollableRange().upperBound()) {
1574 horizontalScrollBar.moveScrollBoxTo(position);
1575 repositionWindow();
1576 }
1577 else {
1578 messageBeep();
1579 }
1580 return true;
1581 }
1582 //default: return false;
1583 }
1584 return false;
1585 }
1586
1587 Boolean AgDataView::mouseClicked(IMouseClickEvent &event) {
1588 //LOGSECTION("AgDataView::mouseClicked", Log::off);
1589 LOGSECTION_OFF("AgDataView::mouseClicked");
1590 LOGV(frameWindow->activeFlag);
1591
1592 unsigned line = event.mousePosition().y()/lineHeight();
1593 line += verticalScrollBar.scrollBoxPosition();
1594 unsigned nLines = windowData->nLines();
1595
1596 if (ControlPanel::helpCursorSet) {
1597 if (event.mouseButton() == IMouseClickEvent::button2) {
1598 return false;
1599 }
1600 if (event.mouseAction() == IMouseClickEvent::down) {
1601 if (line < nLines && line != cursorLine) {
1602 setCursorLine(line).synchCursor(line);
1603 selectAction.performDeferred();
1604 }
1605 showHelp(event);
1606 ControlPanel::helpCursorSet = 0;
1607 ControlPanel::resetCursor();
1608 }
1609 return true;
1610 }
1611
1612 if (event.controlWindow() == &columnHeadTitle
1613 || event.controlWindow() == &verticalScrollBar
1614 || event.controlWindow() == &horizontalScrollBar)
1615 {
1616 if (event.mouseAction() == IMouseClickEvent::down) {
1617 dataArea.setFocus();
1618 }
1619 return false;
1620 }
1621
1622 LOGV(event.mouseButton());
1623 LOGV(event.mouseAction());
1624 LOGV(line);
1625
1626 if (event.mouseButton() == IMouseClickEvent::button2) {
1627 if (!dataArea.hasFocus()) {
1628 dataArea.setFocus();
1629 }
1630 if (line >= nLines) {
1631 return true;
1632 }
1633 /*
1634 if (event.mouseAction() == IMouseClickEvent::down) {
1635 rightButtonDown = true;
1636 }
1637 else if (event.mouseAction() == IMouseClickEvent::up) {
1638 rightButtonDown = false;
1639 }
1640 else if (event.mouseAction() == IMouseClickEvent::click) {
1641 LOGS("right click");
1642 if (line == cursorLine) {
1643 //return true;
1644 return false;
1645 }
1646 setCursorLine(line).synchCursor(line);
1647 selectAction.performDeferred();
1648 return false;
1649 }
1650 */
1651 if (event.mouseAction() == IMouseClickEvent::down) {
1652 rightButtonState = buttonDown;
1653 }
1654 else if (event.mouseAction() == IMouseClickEvent::up) {
1655 rightButtonState = waitingForClick;
1656 if (line == cursorLine) {
1657 return false;
1658 }
1659 setCursorLine(line).synchCursor(line);
1660 selectAction.performDeferred();
1661 return false;
1662 }
1663 else if (event.mouseAction() == IMouseClickEvent::click) {
1664 rightButtonState = buttonIdle;
1665 return false;
1666 }
1667 }
1668 if (line >= nLines && event.mouseAction() == IMouseClickEvent::down) {
1669 if (!dataArea.hasFocus()) {
1670 dataArea.setFocus();
1671 }
1672 return false;
1673 }
1674 if (!mouseDown && line >= nLines) {
1675 return false;
1676 }
1677 if (event.mouseButton() != IMouseClickEvent::button1) {
1678 return false;
1679 }
1680 switch (event.mouseAction()) {
1681 case IMouseClickEvent::down: {
1682 if (event.windowUnderPointer() != dataArea.handle()) {
1683 return false;
1684 }
1685 LOGS("mouse down");
1686 if (!dataArea.hasFocus()) {
1687 dataArea.setFocus();
1688 }
1689 dataArea.capturePointer(true);
1690 mouseDownCursorLine = cursorLine;
1691 if (line != cursorLine) {
1692 setCursorLine(line).synchCursor(line);
1693 selectAction.performDeferred();
1694 }
1695 mouseDown = true;
1696 return true;
1697 }
1698 case IMouseClickEvent::up: {
1699 LOGS("mouse up");
1700 mouseDown = false;
1701 dataArea.capturePointer(false);
1702 return true;
1703 }
1704 case IMouseClickEvent::click: {
1705 if (event.windowUnderPointer() != dataArea.handle()) {
1706 return false;
1707 }
1708 LOGS("mouse click");
1709 return true;
1710 }
1711 case IMouseClickEvent::doubleClick: {
1712 LOGS("double click");
1713 enterAction.performDeferred();
1714 return true;
1715 }
1716 }
1717 return false;
1718 }
1719
1720 Boolean AgDataView::mouseMoved(IMouseEvent &event) {
1721 if (!mouseDown) {
1722 return false;
1723 }
1724 if (mouseTimer.isStarted()) {
1725 mouseTimer.stop();
1726 }
1727 int mouseY = event.mousePosition().y();
1728 if (mouseY < 0) {
1729 mouseY -= lineHeight();
1730 }
1731 int mouseLine = mouseY/lineHeight();
1732 int topLine = verticalScrollBar.scrollBoxPosition();
1733 LOGSECTION("AgDataView::mouseMoved");
1734 LOGV((int) frameWindow);
1735 LOGV(topLine) LCV(mouseLine);
1736 dragMouse(topLine, mouseLine);
1737 if (mouseLine >= 0 && mouseLine < verticalLineCount) {
1738 return true;
1739 }
1740 topLine = verticalScrollBar.scrollBoxPosition();
1741 IReference<ITimerFn> timerFn(new MouseDragTimer(this, topLine, mouseLine));
1742 mouseTimer.start(timerFn, 50);
1743 LOGS("timer started");
1744 return true;
1745 }
1746
1747 void AgDataView::dragMouse(int topLine, int mouseLine) {
1748 LOGSECTION("AgDataView::DragMouse");
1749 LOGV((int) frameWindow);
1750 int bottomLine = topLine + verticalLineCount - 1;
1751 int line = topLine + mouseLine;
1752 if (line < 0) {
1753 line = 0;
1754 }
1755 if (line >= windowData->nLines()) {
1756 line = windowData->nLines() - 1;
1757 }
1758 if (line == cursorLine) {
1759 return;
1760 }
1761 int oldLine = cursorLine;
1762 cursorLine = line;
1763 windowData->synchCursor(cursorLine);
1764 selectAction.performDeferred();
1765 LOGV(topLine);
1766 LOGV(mouseLine);
1767 LOGV(oldLine);
1768 LOGV(cursorLine);
1769 if (cursorLine < topLine) {
1770 repaintLine(oldLine);
1771 verticalScrollBar.moveScrollBoxTo(cursorLine);
1772 repositionWindow();
1773 return;
1774 }
1775 //if (cursorLine > bottomLine + 1) {
1776 if (cursorLine > bottomLine) {
1777 repaintLine(oldLine);
1778 verticalScrollBar.moveScrollBoxTo(topLine + cursorLine - bottomLine);
1779 repositionWindow();
1780 return;
1781 }
1782 else {
1783 repaintLine(oldLine);
1784 repaintLine(cursorLine);
1785 }
1786 LOGV(cursorLine);
1787 windowData->synchCursor(cursorLine);
1788 selectAction.performDeferred();
1789 return;
1790 }
1791
1792 void AgDataView::mouseDragTimerInterrupt(int &topLine, int mouseLine) {
1793 LOGSECTION("AgDataView::mouseDragTimerInterrupt");
1794 LOGV((int) frameWindow);
1795 LOGV(topLine) LCV(mouseLine) LCV(cursorLine);
1796 if (!mouseDown || topLine + mouseLine == cursorLine) {
1797 mouseTimer.stop();
1798 LOGV(mouseDown);
1799 LOGV(topLine) LCV(verticalScrollBar.scrollBoxPosition());
1800 return;
1801 }
1802 if (topLine + mouseLine != cursorLine) {
1803 dragMouse(topLine, mouseLine);
1804 }
1805 topLine = verticalScrollBar.scrollBoxPosition();
1806 }
1807
1808 AgDataView::MouseDragTimer::MouseDragTimer(AgDataView * window_,
1809 int topLine_,
1810 int mouseLine_)
1811 : window(window_)
1812 , topLine(topLine_)
1813 , mouseLine(mouseLine_)
1814 {}
1815
1816 void AgDataView::MouseDragTimer::timerExpired(unsigned long) {
1817 LOGSECTION("AgDataView::MouseDragTimer::timerExpired");
1818 window->mouseDragTimerInterrupt(topLine, mouseLine);
1819 }
1820
1821 Boolean AgDataView::command(ICommandEvent &event) {
1822 unsigned id = event.commandId() - 1;
1823 LOGSECTION("AgDataView::command");
1824 LOGV((int) event.controlWindow());
1825 LOGV((int) event.dispatchingWindow());
1826 LOGV((int) frameWindow);
1827 LOGV((int) id);
1828
1829 if (id >= auxMenu.size()) {
1830 return false;
1831 }
1832 LOGV(ControlPanel::helpCursorSet) LCV(AgFrame::menuShowingFlag);
1833 if (ControlPanel::helpCursorSet) {
1834 ControlPanel::helpCursorSet = 0;
1835 ControlPanel::resetCursor();
1836 AgHelpWindow::showHelp(auxMenu[id].text);
1837 return true;
1838 }
1839
1840 auxMenu[id].action.perform();
1841 return true;
1842 }
1843
1844 AgDataView &AgDataView::initPopUp() {
1845 if (popUpInitialized) {
1846 return *this;
1847 }
1848 popUpInitialized = 1;
1849
1850 LOGSECTION("AgDataView::initPopUp");
1851 LOGV(windowId);
1852 LOGV((int) this);
1853 LOGV((int) frameWindow);
1854 LOGV((int) &popUpMenu);
1855
1856 int n = auxMenu.size();
1857 int i;
1858 for (i = 0; i < n; i++) {
1859 char *text = auxMenu[i].text.pointer();
1860 LOGV(text);
1861 LOGV((int) auxMenu[i].displayControl);
1862 popUpMenu.addText(i+1, text);
1863 }
1864 return *this;
1865 }
1866
1867 AgDataView &AgDataView::validatePopUp() {
1868 LOGSECTION("AgDataView::validatePopUp");
1869 LOGV(windowId) LCV((int) this);
1870 LOGV((int) frameWindow) LCV((int) windowData);
1871 LOGV(windowData->getCursorLine());
1872 LOGV(ControlPanel::helpCursorSet) LCV(AgFrame::menuShowingFlag);
1873
1874 if (ControlPanel::helpCursorSet) {
1875 return *this;
1876 }
1877 int n = auxMenu.size();
1878 LOGV(n);
1879 int i;
1880 for (i = 0; i < n; i++) {
1881 //char *text = auxMenu[i].text.pointer();
1882 //LOGV(text);
1883 dc *d = auxMenu[i].displayControl;
1884 LOGV((int) d);
1885 ok_ptr(d);
1886 dc::MenuOption **option = d->getAuxWinMenu();
1887 #ifdef INCLUDE_LOGGING
1888 LOGV((int) option) LCV((int) option[i]);
1889 union { int(dc::*fun)(); int address; } kluge;
1890 kluge.fun = option[i]->ok_action;
1891 LOGV(kluge.address);
1892 #endif
1893 int flag = ((*d).*(option[i]->ok_action))();
1894 LOGV(flag);
1895 popUpMenu.enableItem(i+1, flag);
1896 }
1897 return *this;
1898 }
1899
1900 Boolean AgDataView::makePopUpMenu(IMenuEvent &event ) {
1901 LOGSECTION("AgDataView::makePopUpMenu");
1902 LOGV(windowId);
1903 LOGV((int) this);
1904 LOGV((int) frameWindow);
1905 if (!auxMenu.exists()) {
1906 return false;
1907 }
1908 IPoint where = dataArea.position();
1909 if (rightButtonState == waitingForClick) {
1910 LOGV(event.mousePosition().asString());
1911 where = event.mousePosition();
1912 }
1913 LOGV(auxMenu.exists());
1914
1915 int n = auxMenu.size();
1916 int i;
1917 for (i = 0; i < n; i++) {
1918 popUpMenu.enableItem(i+1);
1919 }
1920 validatePopUp();
1921
1922 AgFrame::activeAuxMenu = auxMenu;
1923
1924 LOGS("activeAuxMenu has been set");
1925
1926 AgFrame::activePopUpMenu = &popUpMenu;
1927
1928 LOGS("activePopUpMenu has been set");
1929 LOGS("ready to display popUpMenu");
1930
1931 //popUpMenu.show(event.mousePosition());
1932 popUpMenu.show(where);
1933
1934 LOGS("popUpMenu should be visible");
1935
1936 AgFrame::activeAuxMenu.discardData();
1937 AgFrame::activePopUpMenu = 0;
1938
1939 return true;
1940 }
1941
1942 Boolean AgDataView::showHelp(IEvent &event) {
1943 showHelp();
1944 return true;
1945 }
1946
1947 void AgDataView::showHelp() {
1948 AgString topic;
1949 LOGSECTION("AgDataView::showHelp");
1950 int n = popUpMenu.numberOfItems();
1951 for (int i = 0; i++ < n;) {
1952 IMenuItem item = popUpMenu.menuItem(i);
1953 if (item.isHighlighted()) {
1954 topic = auxMenu[i-1].text;
1955 break;
1956 }
1957 }
1958 LOGV(i) LCV(n) LCV(topic);
1959 if (!topic.exists() && helpTopic != 0) {
1960 topic = helpTopic;
1961 }
1962 if (!topic.exists()) {
1963 topic = windowData->findHelpTopic();
1964 }
1965 if (!topic.exists()) {
1966 topic = windowData->headTitle();
1967 }
1968 AgHelpWindow::showHelp(topic);
1969 }
1970
1971 Boolean AgDataView::menuEnded(IMenuEvent &event) {
1972 LOGSECTION("AgDataView::menuEnded");
1973 LOGV((int) frameWindow);
1974 LOGV(ControlPanel::helpCursorSet) LCV(AgFrame::menuShowingFlag);
1975 if (!ControlPanel::helpCursorSet) {
1976 frameWindow->activeAuxMenu.discardData();
1977 }
1978 return true;
1979 }
1980