Add GNU LGPL headers to all .c .C and .h files
[oweals/cde.git] / cde / programs / dtinfo / dtinfo / src / Basic / NodeViewInfo.C
1 /*
2  * CDE - Common Desktop Environment
3  *
4  * Copyright (c) 1993-2012, The Open Group. All rights reserved.
5  *
6  * These libraries and programs are free software; you can
7  * redistribute them and/or modify them under the terms of the GNU
8  * Lesser General Public License as published by the Free Software
9  * Foundation; either version 2 of the License, or (at your option)
10  * any later version.
11  *
12  * These libraries and programs are distributed in the hope that
13  * they will be useful, but WITHOUT ANY WARRANTY; without even the
14  * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15  * PURPOSE. See the GNU Lesser General Public License for more
16  * details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with these librararies and programs; if not, write
20  * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
21  * Floor, Boston, MA 02110-1301 USA
22  */
23 /*      Copyright (c) 1996 FUJITSU LIMITED      */
24 /*      All Rights Reserved                     */
25
26 /*
27  * $XConsortium: NodeViewInfo.C /main/17 1996/11/18 15:50:15 mustafa $
28  *
29  * Copyright (c) 1993 HAL Computer Systems International, Ltd.
30  * All rights reserved.  Unpublished -- rights reserved under
31  * the Copyright Laws of the United States.  USE OF A COPYRIGHT
32  * NOTICE IS PRECAUTIONARY ONLY AND DOES NOT IMPLY PUBLICATION
33  * OR DISCLOSURE.
34  * 
35  * THIS SOFTWARE CONTAINS CONFIDENTIAL INFORMATION AND TRADE
36  * SECRETS OF HAL COMPUTER SYSTEMS INTERNATIONAL, LTD.  USE,
37  * DISCLOSURE, OR REPRODUCTION IS PROHIBITED WITHOUT THE
38  * PRIOR EXPRESS WRITTEN PERMISSION OF HAL COMPUTER SYSTEMS
39  * INTERNATIONAL, LTD.
40  * 
41  *                         RESTRICTED RIGHTS LEGEND
42  * Use, duplication, or disclosure by the Government is subject
43  * to the restrictions as set forth in subparagraph (c)(l)(ii)
44  * of the Rights in Technical Data and Computer Software clause
45  * at DFARS 252.227-7013.
46  *
47  *          HAL COMPUTER SYSTEMS INTERNATIONAL, LTD.
48  *                  1315 Dell Avenue
49  *                  Campbell, CA  95008
50  * 
51  */
52
53 #include <limits.h>
54 #include <wchar.h>
55
56 #define C_NodeViewInfo
57 #define L_Basic
58
59 #define C_xList
60 #define L_Support
61
62 #define C_PixmapGraphic
63 #define L_Graphics
64
65 #define C_GraphicsMgr
66 #define C_MessageMgr
67 #define C_NodeMgr
68 #define C_NodeParser
69 #define L_Managers
70
71 #include "Prelude.h"
72
73 #include <DtI/LinkMgrP.h>
74
75 #undef self
76 #include <DtI/DisplayAreaP.h>
77 #include <DtI/FontI.h>
78 #include <DtI/FontAttrI.h>
79 #include <DtI/RegionI.h>
80
81 #include "OnlineRender/SegClientData.hh"
82
83 #include "UAS/DtSR/Util_Classes/DictIter.hh"
84
85 // /////////////////////////////////////////////////////////////////
86 // class constructor
87 // /////////////////////////////////////////////////////////////////
88
89 NodeViewInfo::NodeViewInfo (UAS_Pointer<UAS_Common> &node_ptr, _DtCvTopicInfo *topic)
90 : f_node_ptr (node_ptr),
91   f_topic(topic),
92   f_current_hit(NULL),
93   f_def_key(""),
94   f_def_val((unsigned long)-1),
95   f_color_dict(f_def_key, f_def_val)
96 {
97 #ifdef DEBUG
98   printf( "make NodeViewInfo %p\n\n", this );
99 #endif
100 }
101
102
103 /*
104    Recursively clean up our segment structures
105 */
106 static void
107 cleanup(_DtCvSegment *segment)
108 {
109   if (segment)
110     {
111       switch (segment->type & _DtCvPRIMARY_MASK)
112         {
113         case _DtCvCONTAINER:
114           if (segment->handle.container.id)
115             free (segment->handle.container.id);
116           cleanup (segment->handle.container.seg_list);
117           break;
118         case _DtCvSTRING:
119             if (segment->handle.string.string)
120                 delete (segment->handle.string.string);
121           if (segment->client_use) {
122             delete (SegClientData*)segment->client_use;
123             segment->client_use = NULL;
124           }
125           break;
126         case _DtCvTABLE:
127           {
128             _DtCvTable *table = &segment->handle.table ;
129             if (table->col_w)
130               {
131                 for (int i = 0 ; i < table->num_cols; i++)
132                   delete table->col_w[i] ;
133                 delete table->col_w ;
134
135               }
136             delete table->col_justify ;
137             delete table->justify_chars ;
138             char **ids = table->cell_ids ;
139             while (*ids)
140               delete *ids++ ;
141             delete table->cell_ids ;
142             _DtCvSegment **cells = table->cells ;
143             while (*cells)
144               cleanup(*cells++);
145             delete table->cells ;
146           }
147           break ;
148         case _DtCvMARKER:
149           delete segment->handle.marker ;
150           break;
151         case _DtCvREGION:
152           {
153             _DtHelpDARegion     *pReg = (_DtHelpDARegion*) segment->handle.region.info ;
154             DtHelpGraphicStruct *pGS  = (DtHelpGraphicStruct *) pReg->handle;
155             delete pGS ;
156             delete pReg ;
157             if (segment->client_use) {
158               // Note: ((SegClientData*)segment->client_use)->GraphicHandle()
159               //       is deleted separately through f_pixmap_list
160               delete (SegClientData*)segment->client_use;
161               segment->client_use = NULL;
162             }
163           }
164           break ;
165         }
166       cleanup(segment->next_seg);
167
168       delete segment;
169     }
170 }
171
172 // /////////////////////////////////////////////////////////////////
173 // class destructor
174 // /////////////////////////////////////////////////////////////////
175
176 NodeViewInfo::~NodeViewInfo()
177 {
178   _DtLinkDbDestroy(f_topic->link_data); // kill the link database
179
180   cleanup(f_topic->seg_list);   // kill the segments and their items
181
182   f_topic->seg_list = 0 ;
183   delete f_topic ;              // sayonara
184
185   if (f_pixmap_list != NULL)
186   {             // explicitly cleanup graphics in f_pixmap_list
187     List_Iterator<UAS_Pointer<Graphic> > gli (f_pixmap_list) ;
188     while (gli)
189     {
190 #ifdef DEBUG
191       printf( "delete UAS_Pointer<Graphic> gli.item() = %p\n", gli.item() );
192 #endif
193       f_pixmap_list.remove(gli) ;
194     }
195   }
196 #ifdef DEBUG
197   printf( "kill NodeViewInfo %p\n\n", this );
198 #endif
199 }
200
201 void
202 NodeViewInfo::add_graphic(UAS_Pointer<Graphic> &pg)
203 {
204   f_pixmap_list.append(pg);
205
206 #ifdef DEBUG
207   printf( "NodeViewInfo: add UAS_Pointer<Graphic> %p\n", pg );
208   if (f_pixmap_list != NULL)
209   {
210       List_Iterator<UAS_Pointer<Graphic> > gli (f_pixmap_list) ;
211       printf( "graphics list is now: " );
212       while (gli)
213       {
214         printf( " %p ", gli.item() );
215         gli++;
216       }
217       printf( "\n" );
218   }
219 #endif
220 }
221
222 static unsigned int
223 DtCvStrLen(_DtCvSegment* seg)
224 {
225     if (seg == NULL || (seg->type & _DtCvPRIMARY_MASK) != _DtCvSTRING)
226         return 0;
227
228     unsigned int len = 0;
229
230     if (seg->type & _DtCvWIDE_CHAR) {
231         wchar_t* seg_str = (wchar_t*)seg->handle.string.string;
232         for (; *seg_str; seg_str++, len++);
233     }
234     else {
235         char* seg_str = (char*)seg->handle.string.string;
236         for (; *seg_str; seg_str++, len++);
237     }
238
239     return len;
240 }
241
242 static unsigned int
243 DtCvStrVccToIndex(_DtCvSegment* seg, unsigned int vcc)
244 {
245     if (seg == NULL || (seg->type & _DtCvPRIMARY_MASK) != _DtCvSTRING
246                     || seg->client_use == NULL)
247         return (unsigned int)-1;
248
249     unsigned int index = 0;
250
251     unsigned int rel_vcc;
252     if ((rel_vcc = vcc - ((SegClientData*)seg->client_use)->vcc()) < 0)
253         return (unsigned int)-1;
254
255     if (seg->type & _DtCvWIDE_CHAR) {
256         wchar_t* seg_str = (wchar_t*)seg->handle.string.string;
257         for (; *seg_str && rel_vcc > 0; seg_str++, index++) {
258             if (*seg_str != ' ' && *seg_str != '\t' && *seg_str != '\n')
259                 rel_vcc--;
260         }
261         if (*seg_str == 0 && rel_vcc > 0)
262             index = (unsigned int)-1;
263         else {
264             for (; *seg_str; seg_str++, index++) {
265                 if (*seg_str != ' ' && *seg_str != '\t' && *seg_str != '\n')
266                     break;
267             }
268         }
269     }
270     else {
271         unsigned char* seg_str = (unsigned char*)seg->handle.string.string;
272         for (; *seg_str && rel_vcc > 0; seg_str++, index++) {
273             if (*seg_str != ' ' && *seg_str != '\t' &&
274                                    *seg_str != '\n' && *seg_str != 0xA0)
275                 rel_vcc--;
276         }
277         if (*seg_str == 0 && rel_vcc > 0)
278             index = (unsigned int)-1;
279         else {
280             for (; *seg_str; seg_str++, index++) {
281                 if (*seg_str != ' ' && *seg_str != '\t' &&
282                                        *seg_str != '\n' && *seg_str != 0xA0)
283                     break;
284             }
285         }
286     }
287
288     return index;
289 }
290
291 static unsigned int
292 DtCvStrVcLenSync(_DtCvSegment* seg)
293 {
294     if (seg == NULL || (seg->type & _DtCvPRIMARY_MASK) != _DtCvSTRING
295                     || seg->client_use == NULL)
296         return (unsigned int)-1;
297
298     unsigned int vclen = 0;
299
300     if (seg->type & _DtCvWIDE_CHAR) {
301         wchar_t* seg_str = (wchar_t*)seg->handle.string.string;
302         for (; *seg_str; seg_str++) {
303             if (*seg_str != ' ' && *seg_str != '\t' && *seg_str != '\n')
304                 vclen++;
305         }
306     }
307     else {
308         unsigned char* seg_str = (unsigned char*)seg->handle.string.string;
309         for (; *seg_str; seg_str++) {
310             if (*seg_str != ' ' && *seg_str != '\t' &&
311                                    *seg_str != '\n' && *seg_str != 0xA0)
312                 vclen++;
313         }
314     }
315
316     // synchronization
317     ((SegClientData*)seg->client_use)->vclen() = vclen;
318
319     return vclen;
320 }
321
322 static unsigned int
323 DtCvStrVcLen(_DtCvSegment* seg)
324 {
325     if (seg == NULL || (seg->type & _DtCvPRIMARY_MASK) != _DtCvSTRING)
326         return 0;
327
328     return ((SegClientData*)seg->client_use)->vclen();
329 }
330
331 static unsigned int
332 DtCvStrVcc(_DtCvSegment* seg)
333 {
334     if (seg == NULL || (seg->type & _DtCvPRIMARY_MASK) != _DtCvSTRING
335                     || seg->client_use == NULL)
336         return (unsigned int)-1;
337
338     return ((SegClientData*)seg->client_use)->vcc();
339 }
340
341 static void
342 DtCvStrVcc(_DtCvSegment* seg, unsigned int vcc)
343 {
344     if (seg == NULL || (seg->type & _DtCvPRIMARY_MASK) != _DtCvSTRING
345                     || seg->client_use == NULL)
346         return;
347
348     ((SegClientData*)seg->client_use)->vcc() = vcc;
349 }
350
351 // Chop a segment into two separate segments.
352 // nc is the number of characters of the first segment.
353
354 _DtCvSegment*
355 chop_segment(_DtCvSegment* seg, unsigned int nc)
356 {
357     if (seg == NULL || (seg->type & _DtCvPRIMARY_MASK) != _DtCvSTRING)
358         return NULL;
359
360     if (nc == 0)
361         return NULL;
362
363     unsigned int seg_nc = DtCvStrLen(seg);
364
365     if (nc == seg_nc) {
366         assert( nc > 0 );
367         return seg;
368     }
369
370     unsigned long widec = seg->type & _DtCvWIDE_CHAR;
371
372     void* nseg_str;
373     if (widec) {
374         wchar_t* src  = (wchar_t*)seg->handle.string.string + nc;
375         wchar_t* dest = new wchar_t[seg_nc - nc + 1];
376         for (int i = 0; i < seg_nc - nc; i++)
377             dest[i] = src[i];
378         dest[seg_nc - nc] = '\0';
379         nseg_str = (void*)dest;
380
381         wchar_t* seg_str = (wchar_t*)seg->handle.string.string;
382         seg_str[nc] = '\0'; // chop seg string
383     }
384     else {
385         char* src  = (char*)seg->handle.string.string + nc;
386         char* dest = new char[seg_nc - nc + 1];
387         for (int i = 0; i < seg_nc - nc; i++)
388             dest[i] = src[i];
389         dest[seg_nc - nc] = '\0';
390         nseg_str = (void*)dest;
391
392         unsigned char* seg_str = (unsigned char*)seg->handle.string.string;
393         seg_str[nc] = '\0'; // chop seg string
394     }
395     DtCvStrVcLenSync(seg);
396
397     unsigned int seg_vcc   = DtCvStrVcc(seg);
398     unsigned int seg_vclen = DtCvStrVcLen(seg);
399
400 #ifdef SYMBOL_HIGHLIGHT
401     _DtCvSegment* symseg = new _DtCvSegment(*seg);
402     symseg->next_seg  = seg->next_seg;
403     symseg->next_disp = seg->next_disp;
404     seg ->next_seg  = symseg;
405     seg ->next_disp = symseg;
406
407     symseg->handle.string.string = new char[2];
408     *(unsigned char*) symseg->handle.string.string      = 0xA4;
409     *((unsigned char*)symseg->handle.string.string + 1) = 0x00;
410     symseg->client_use   = NULL;
411     symseg->internal_use = NULL;
412     symseg->type |=  _DtCvAPP_FLAG1;
413     symseg->type &= ~_DtCvWIDE_CHAR;
414
415     if (symseg->type & _DtCvNEW_LINE) // take _DtCvNEW_LINE over
416         seg->type &= ~_DtCvNEW_LINE;
417
418     symseg->type &=
419                 ~(_DtCvSEARCH_FLAG | _DtCvSEARCH_BEGIN | _DtCvSEARCH_END);
420
421     seg = symseg;
422 #endif
423
424     _DtCvSegment* nseg = new _DtCvSegment(*seg);
425     nseg->next_seg  = seg->next_seg;
426     nseg->next_disp = seg->next_disp;
427     seg ->next_seg  = nseg;
428     seg ->next_disp = nseg;
429
430     if (nseg->type & _DtCvNEW_LINE) // take _DtCvNEW_LINE over
431         seg->type &= ~_DtCvNEW_LINE;
432
433     if (widec)
434         nseg->type |= _DtCvWIDE_CHAR;
435
436     nseg->type &= ~_DtCvAPP_FLAG1;
437
438     nseg->type &= ~(_DtCvSEARCH_FLAG | _DtCvSEARCH_BEGIN | _DtCvSEARCH_END);
439
440     nseg->internal_use = NULL;
441
442     nseg->handle.string.string = nseg_str;
443
444     // set client_use properly
445     nseg->client_use = (_DtCvPointer)new SegClientData(_DtCvSTRING);
446     DtCvStrVcc(nseg, seg_vcc + seg_vclen);
447     DtCvStrVcLenSync(nseg);
448
449     return nseg;
450 }
451
452 // FUNCTION highlight_search_hit
453 // INPUT
454 //   vcc : vcc of the segment to be highlighted
455 //   len : character length of the segment to be highlighted
456 //
457 // RETURN
458 //   the segment to be highlighted
459
460 _DtCvSegment*
461 highlight_search_hit(_DtCvSegment* seg, unsigned int vcc, unsigned int len)
462 {
463     if (seg == NULL || (seg->type & _DtCvPRIMARY_MASK) != _DtCvSTRING)
464         return NULL;
465
466     if (len <= 0)
467         return NULL;
468
469     unsigned int seg_vcc = DtCvStrVcc(seg);
470     unsigned int seg_nc  = DtCvStrLen(seg);
471
472     if (vcc < seg_vcc) // vcc falls short
473         return NULL;
474
475     unsigned long widec = seg->type & _DtCvWIDE_CHAR;
476
477     // translate rel_vcc (vccs) into nseg_nc (characters)
478     unsigned int nseg_nc = DtCvStrVccToIndex(seg, vcc);
479     if (nseg_nc == (unsigned int)-1) // vcc is beyond segment
480         return NULL;
481
482 #ifdef DEBUG
483     fprintf(stderr, "(DEBUG) vcc=%d, index=%d, clen=%d\n", vcc, nseg_nc, len);
484 #endif
485
486     if (len == 0)
487         return NULL;
488     else if (seg_vcc == vcc && seg_nc == len)
489         return seg;
490
491     if (len > seg_nc - nseg_nc) { // len goes beyond this segment
492         if (seg->next_seg == NULL) {
493             len = seg_nc - nseg_nc;
494         }
495         else {
496             _DtCvSegment* sibling = seg->next_seg;
497             unsigned long type = sibling->type & _DtCvPRIMARY_MASK;
498             if (type != _DtCvSTRING || sibling->client_use == NULL ||
499                 DtCvStrVcc(sibling) == (unsigned int)-1 ||
500                 (seg->type & _DtCvWIDE_CHAR) != (sibling->type & _DtCvWIDE_CHAR)) {
501                 len = seg_nc - nseg_nc;
502             }
503             else { // let's merge segments
504                 seg->next_seg  = sibling->next_seg;
505                 seg->next_disp = sibling->next_disp;
506                 sibling->next_seg = NULL;
507                 sibling->next_disp = NULL;
508                 
509                 if (widec) {
510                     wchar_t* src = (wchar_t*)sibling->handle.string.string;
511                     wchar_t* dst = (wchar_t*)seg->handle.string.string;
512                     int len = wcslen(dst) + wcslen(src);
513                     seg->handle.string.string = (void*)
514                         realloc(seg->handle.string.string,
515                                         sizeof(wchar_t) * (len + 1));
516                     dst = (wchar_t*)seg->handle.string.string;
517                     wcscat(dst, src);
518                 }
519                 else {
520                     char* src = (char*)sibling->handle.string.string;
521                     char* dst = (char*)seg->handle.string.string;
522                     int len = strlen(dst) + strlen(dst);
523                     seg->handle.string.string = (void*)
524                         realloc(seg->handle.string.string, len + 1);
525                     dst = (char*)seg->handle.string.string;
526                     strcat(dst, src);
527                 }
528                 DtCvStrVcLenSync(seg);
529
530                 if (sibling->handle.string.string)
531                     free (sibling->handle.string.string);
532                 if (sibling->client_use) {
533                     delete sibling->client_use;
534                     sibling->client_use = NULL;
535                 }
536
537                 // NOTE: sibling is kept (i.e. not deleted)
538                 // this fact may cause problems in next highlight_search_hit
539
540                 return highlight_search_hit(seg, vcc, len);
541             }
542         }
543     }
544
545     if (nseg_nc) {
546 #ifdef DEBUG    
547         if (widec) {
548             char buf[MB_LEN_MAX + 1];
549             wchar_t* debug_p = (wchar_t*)seg->handle.string.string + nseg_nc;
550             int n = wctomb(buf, *debug_p);
551             assert( n >= 0 );
552             *(buf + n) = '\0';
553             fprintf(stderr, "(DEBUG) initial=%s\n", buf);
554         }
555         else {
556             char* debug_p = (char*)seg->handle.string.string + nseg_nc;
557             fprintf(stderr, "(DEBUG) initial=%c\n", *debug_p);
558         }
559 #endif
560         if ((seg = chop_segment(seg, nseg_nc)) == NULL)
561             return NULL;
562     }
563
564     if (len != seg_nc - nseg_nc)
565         chop_segment(seg, len);
566
567     return seg;
568 }
569
570 static _DtCvSegment *
571 traverse_for_vcc(_DtCvSegment* seg, unsigned int vcc)
572 {
573     if (seg == NULL)
574         return NULL;
575
576     unsigned long seg_ptype = seg->type & _DtCvPRIMARY_MASK;
577
578     if (seg_ptype == _DtCvSTRING && seg->client_use) {
579
580         assert( DtCvStrVcc(seg) <= vcc );
581
582         if (DtCvStrVcc(seg) != (unsigned int)-1) { // check for validity
583             if (vcc < DtCvStrVcc(seg) + DtCvStrVcLen(seg)) // found
584                 return seg;
585         }
586     }
587
588     _DtCvSegment* therein = NULL;
589
590     if (seg_ptype == _DtCvCONTAINER) { // traverse subordinates
591         _DtCvSegment* subordinates;
592         if ((subordinates = seg->handle.container.seg_list) != NULL)
593             therein = traverse_for_vcc(subordinates, vcc);
594     }
595     else if (seg_ptype == _DtCvTABLE) {
596         _DtCvSegment** cell = seg->handle.table.cells;
597         for (; *cell; cell++) {
598             if (therein = traverse_for_vcc(*cell, vcc))
599                 break;
600         }
601     }
602     if (therein)
603         return therein;
604
605     // traverse siblings
606     _DtCvSegment* siblings;
607     if ((siblings = seg->next_seg) != NULL)
608         therein = traverse_for_vcc(siblings, vcc);
609
610     return therein;
611 }
612
613 _DtCvSegment*
614 NodeViewInfo::top_container()
615 {
616     if (f_topic == NULL)
617         return NULL;
618
619     // retrieve the top container
620     _DtCvSegment* root_seg;
621     if ((root_seg = f_topic->seg_list) == NULL)
622         return NULL;
623     assert( (root_seg->type & _DtCvPRIMARY_MASK) == _DtCvCONTAINER );
624
625     return root_seg;
626 }
627
628 void
629 clear_search_hits_traverse(_DtCvSegment* seg)
630 {
631     if (seg == NULL)
632         return;
633
634     unsigned long seg_ptype = seg->type & _DtCvPRIMARY_MASK;
635
636     if (seg_ptype == _DtCvSTRING && seg->client_use) {
637         if (seg->type & _DtCvSEARCH_FLAG)
638             seg->type &=
639                 ~(_DtCvSEARCH_FLAG | _DtCvSEARCH_BEGIN | _DtCvSEARCH_END |
640                   _DtCvAPP_FLAG2);
641     }
642
643     if (seg_ptype == _DtCvCONTAINER) { // traverse subordinates
644         _DtCvSegment* subordinates;
645         if ((subordinates = seg->handle.container.seg_list) != NULL)
646             clear_search_hits_traverse(subordinates);
647     }
648     else if (seg_ptype == _DtCvTABLE) {
649         _DtCvSegment** cell = seg->handle.table.cells;
650         for (; *cell; cell++)
651             clear_search_hits_traverse(*cell);
652     }
653
654     // traverse siblings
655     _DtCvSegment* siblings;
656     if ((siblings = seg->next_seg) != NULL)
657         clear_search_hits_traverse(siblings);
658
659     return;
660 }
661
662 void
663 NodeViewInfo::clear_search_hits()
664 {
665     // retrieve the top container
666     _DtCvSegment* root_seg;
667     if ((root_seg = top_container()) == NULL)
668         return;
669
670     clear_search_hits_traverse(root_seg);
671
672     f_hits.clearAndDestroy();
673     f_current_hit = NULL;
674 }
675
676 void
677 NodeViewInfo::set_search_hits(UAS_Pointer<UAS_List<UAS_TextRun> >& hits)
678 {
679     if (f_current_hit) { // clear search hits previously displayed
680         clear_search_hits();
681     }
682
683     // retrieve the top container
684     _DtCvSegment* root_seg;
685     if ((root_seg = top_container()) == NULL)
686         return;
687
688     unsigned int idx;
689
690     for (idx = 0; idx < hits->length(); idx++) { // for each TextRun
691
692         UAS_Pointer<UAS_TextRun>& hit = hits->item(idx);
693
694         _DtCvSegment* seg;
695
696         if ((seg = traverse_for_vcc(root_seg, hit->offset())) == NULL) {
697 #ifdef DEBUG
698             fprintf(stderr, "(DEBUG) traverse_for_vcc failed, offset=%d\n",
699                                                                 hit->offset());
700 #endif
701             continue;
702         }
703 #ifdef DEBUG
704         else
705             fprintf(stderr, "(DEBUG) traverse_for_vcc succeeded, offset=%d\n",
706                                                                 hit->offset());
707 #endif
708
709         assert( (seg->type & _DtCvPRIMARY_MASK) == _DtCvSTRING );
710
711         if (seg = highlight_search_hit(seg, hit->offset(), hit->length())) {
712 #ifdef DEBUG
713             fprintf(stderr, "(DEBUG) highlight_search_hit succeeded, "
714                                                 "offset=%d\n", hit->offset());
715 #endif
716             seg->type |=
717                         _DtCvSEARCH_FLAG | _DtCvSEARCH_BEGIN | _DtCvSEARCH_END;
718
719             sr_DtCvSegment* sr_seg = new sr_DtCvSegment(seg);
720
721             if (idx == 0) {
722                 seg->type |= _DtCvAPP_FLAG2;
723                 f_current_hit = sr_seg;
724             }
725             f_hits.append(sr_seg);
726         }
727 #ifdef DEBUG
728         else
729             fprintf(stderr, "(DEBUG) highlight_search_hit failed, offset=%d\n",
730                                                                 hit->offset());
731 #endif
732     }
733 }
734
735 // returns 0 if upon success. returns -1 if it traversal was not changed.
736
737 NodeViewInfo::trav_status_t
738 NodeViewInfo::adjust_current_search_hit(trav_dir_t dir)
739 {
740     trav_status_t status = SUCCESS;
741
742     CC_TPtrDlistIterator<sr_DtCvSegment> iter(f_hits);
743
744     for (++iter; *iter.key() != *f_current_hit;)
745         ++iter;
746
747     if (dir == PREV) {
748         if (*iter.key() != *f_hits.first())
749             --iter;
750     }
751     else {
752         assert( dir == NEXT );
753         if (*iter.key() != *f_hits.last())
754             ++iter;
755     }
756
757     if (*f_current_hit != *iter.key()) {
758         f_current_hit->hitseg->type &= ~_DtCvAPP_FLAG2;
759
760         f_current_hit = iter.key();
761         f_current_hit->hitseg->type |=  _DtCvAPP_FLAG2;
762
763         if (dir == PREV) {
764             if (*f_current_hit == *f_hits.first())
765                 status = REACH_LIMIT;
766         }
767         else
768             if (*f_current_hit == *f_hits.last())
769                 status = REACH_LIMIT;
770     }
771     else
772         status = NOT_MOVED;
773
774     return status;
775 }
776
777 int
778 NodeViewInfo::hit_entries() const
779 {
780     return f_hits.entries();
781 }
782
783 int
784 NodeViewInfo::search_hit_idx()
785 {
786     int i;
787
788     CC_TPtrDlistIterator<sr_DtCvSegment> iter(f_hits);
789
790     for (i = 0, ++iter; *iter.key() != *f_current_hit; i++)
791         ++iter;
792
793     return i;
794 }
795
796 void
797 NodeViewInfo::comp_pixel_values_traverse(_DtCvSegment* seg, Display* dpy,
798                                          Colormap &cmap)
799 {
800     if (seg == NULL)
801         return;
802
803     unsigned long seg_ptype = seg->type & _DtCvPRIMARY_MASK;
804
805     if (seg_ptype == _DtCvSTRING && seg->client_use) {
806         XColor screen, exact;
807         SegClientData* pSCD = (SegClientData*)seg->client_use;
808         assert( pSCD->type() == _DtCvSTRING );
809
810         if (pSCD->bg_color() && pSCD->bg_pixel() == (unsigned long)-1) {
811             UAS_String bg_color = pSCD->bg_color();
812             unsigned long& bg_pixel = f_color_dict[bg_color];
813             if (bg_pixel == (unsigned long)-1) {
814                 if (XAllocNamedColor(dpy, cmap, pSCD->bg_color(),
815                                                         &screen, &exact))
816                     pSCD->bg_pixel(bg_pixel = screen.pixel);
817             }
818             else
819                 pSCD->bg_pixel(bg_pixel);
820         }
821
822         if (pSCD->fg_color() && pSCD->fg_pixel() == (unsigned long)-1) {
823             UAS_String fg_color = pSCD->fg_color();
824             unsigned long& fg_pixel = f_color_dict[fg_color];
825             if (fg_pixel == (unsigned long)-1) {
826                 if (XAllocNamedColor(dpy, cmap, pSCD->fg_color(),
827                                                         &screen, &exact))
828                     pSCD->fg_pixel(fg_pixel = screen.pixel);
829             }
830             else
831                 pSCD->fg_pixel(fg_pixel);
832         }
833     }
834
835     if (seg_ptype == _DtCvCONTAINER) { // traverse subordinates
836         _DtCvSegment* subordinates;
837         if ((subordinates = seg->handle.container.seg_list) != NULL)
838             comp_pixel_values_traverse(subordinates, dpy, cmap);
839     }
840
841     // traverse siblings
842     _DtCvSegment* siblings;
843     if ((siblings = seg->next_seg) != NULL)
844         comp_pixel_values_traverse(siblings, dpy, cmap);
845
846     return;
847 }
848
849 void
850 NodeViewInfo::comp_pixel_values(Display* dpy, Colormap &cmap)
851 {
852     // retrieve the top container
853     _DtCvSegment* root_seg;
854     if ((root_seg = top_container()) == NULL)
855         return;
856
857     comp_pixel_values_traverse(root_seg, dpy, cmap);
858
859 #ifdef CM_DEBUG
860     DictIter<UAS_String, unsigned long> dictiter;
861     for (dictiter = f_color_dict.first(); dictiter() ; dictiter++) {
862         fprintf(stderr, "(DEBUG) color=\"%s\", pixel=0x%lx\n",
863                                 (char*)dictiter.key(), dictiter.value());
864     }
865 #endif
866
867     return;
868 }
869
870 _DtCvSegment*
871 NodeViewInfo::get_segment(unsigned int vcc)
872 {
873   return traverse_for_vcc(top_container(), vcc);
874 }
875
876 unsigned int
877 NodeViewInfo::segment_to_vcc(_DtCvSegment* seg)
878 {
879   return DtCvStrVcc(seg);
880 }
881