OpenIndiana and Solaris port
[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 (char*)(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",
192                 (void*)gli.item() );
193 #endif
194       f_pixmap_list.remove(gli) ;
195     }
196   }
197 #ifdef DEBUG
198   printf( "kill NodeViewInfo %p\n\n", this );
199 #endif
200 }
201
202 void
203 NodeViewInfo::add_graphic(UAS_Pointer<Graphic> &pg)
204 {
205   f_pixmap_list.append(pg);
206
207 #ifdef DEBUG
208   printf( "NodeViewInfo: add UAS_Pointer<Graphic> %p\n", (void*)pg );
209   if (f_pixmap_list != NULL)
210   {
211       List_Iterator<UAS_Pointer<Graphic> > gli (f_pixmap_list) ;
212       printf( "graphics list is now: " );
213       while (gli)
214       {
215         printf( " %p ", (void*)gli.item() );
216         gli++;
217       }
218       printf( "\n" );
219   }
220 #endif
221 }
222
223 static unsigned int
224 DtCvStrLen(_DtCvSegment* seg)
225 {
226     if (seg == NULL || (seg->type & _DtCvPRIMARY_MASK) != _DtCvSTRING)
227         return 0;
228
229     unsigned int len = 0;
230
231     if (seg->type & _DtCvWIDE_CHAR) {
232         wchar_t* seg_str = (wchar_t*)seg->handle.string.string;
233         for (; *seg_str; seg_str++, len++);
234     }
235     else {
236         char* seg_str = (char*)seg->handle.string.string;
237         for (; *seg_str; seg_str++, len++);
238     }
239
240     return len;
241 }
242
243 static unsigned int
244 DtCvStrVccToIndex(_DtCvSegment* seg, unsigned int vcc)
245 {
246     if (seg == NULL || (seg->type & _DtCvPRIMARY_MASK) != _DtCvSTRING
247                     || seg->client_use == NULL)
248         return (unsigned int)-1;
249
250     unsigned int index = 0;
251
252     unsigned int rel_vcc;
253     if ((int)(rel_vcc = vcc - ((SegClientData*)seg->client_use)->vcc()) < 0)
254         return (unsigned int)-1;
255
256     if (seg->type & _DtCvWIDE_CHAR) {
257         wchar_t* seg_str = (wchar_t*)seg->handle.string.string;
258         for (; *seg_str && rel_vcc > 0; seg_str++, index++) {
259             if (*seg_str != ' ' && *seg_str != '\t' && *seg_str != '\n')
260                 rel_vcc--;
261         }
262         if (*seg_str == 0 && rel_vcc > 0)
263             index = (unsigned int)-1;
264         else {
265             for (; *seg_str; seg_str++, index++) {
266                 if (*seg_str != ' ' && *seg_str != '\t' && *seg_str != '\n')
267                     break;
268             }
269         }
270     }
271     else {
272         unsigned char* seg_str = (unsigned char*)seg->handle.string.string;
273         for (; *seg_str && rel_vcc > 0; seg_str++, index++) {
274             if (*seg_str != ' ' && *seg_str != '\t' &&
275                                    *seg_str != '\n' && *seg_str != 0xA0)
276                 rel_vcc--;
277         }
278         if (*seg_str == 0 && rel_vcc > 0)
279             index = (unsigned int)-1;
280         else {
281             for (; *seg_str; seg_str++, index++) {
282                 if (*seg_str != ' ' && *seg_str != '\t' &&
283                                        *seg_str != '\n' && *seg_str != 0xA0)
284                     break;
285             }
286         }
287     }
288
289     return index;
290 }
291
292 static unsigned int
293 DtCvStrVcLenSync(_DtCvSegment* seg)
294 {
295     if (seg == NULL || (seg->type & _DtCvPRIMARY_MASK) != _DtCvSTRING
296                     || seg->client_use == NULL)
297         return (unsigned int)-1;
298
299     unsigned int vclen = 0;
300
301     if (seg->type & _DtCvWIDE_CHAR) {
302         wchar_t* seg_str = (wchar_t*)seg->handle.string.string;
303         for (; *seg_str; seg_str++) {
304             if (*seg_str != ' ' && *seg_str != '\t' && *seg_str != '\n')
305                 vclen++;
306         }
307     }
308     else {
309         unsigned char* seg_str = (unsigned char*)seg->handle.string.string;
310         for (; *seg_str; seg_str++) {
311             if (*seg_str != ' ' && *seg_str != '\t' &&
312                                    *seg_str != '\n' && *seg_str != 0xA0)
313                 vclen++;
314         }
315     }
316
317     // synchronization
318     ((SegClientData*)seg->client_use)->vclen() = vclen;
319
320     return vclen;
321 }
322
323 static unsigned int
324 DtCvStrVcLen(_DtCvSegment* seg)
325 {
326     if (seg == NULL || (seg->type & _DtCvPRIMARY_MASK) != _DtCvSTRING)
327         return 0;
328
329     return ((SegClientData*)seg->client_use)->vclen();
330 }
331
332 static unsigned int
333 DtCvStrVcc(_DtCvSegment* seg)
334 {
335     if (seg == NULL || (seg->type & _DtCvPRIMARY_MASK) != _DtCvSTRING
336                     || seg->client_use == NULL)
337         return (unsigned int)-1;
338
339     return ((SegClientData*)seg->client_use)->vcc();
340 }
341
342 static void
343 DtCvStrVcc(_DtCvSegment* seg, unsigned int vcc)
344 {
345     if (seg == NULL || (seg->type & _DtCvPRIMARY_MASK) != _DtCvSTRING
346                     || seg->client_use == NULL)
347         return;
348
349     ((SegClientData*)seg->client_use)->vcc() = vcc;
350 }
351
352 // Chop a segment into two separate segments.
353 // nc is the number of characters of the first segment.
354
355 _DtCvSegment*
356 chop_segment(_DtCvSegment* seg, unsigned int nc)
357 {
358     if (seg == NULL || (seg->type & _DtCvPRIMARY_MASK) != _DtCvSTRING)
359         return NULL;
360
361     if (nc == 0)
362         return NULL;
363
364     unsigned int seg_nc = DtCvStrLen(seg);
365
366     if (nc == seg_nc) {
367         assert( nc > 0 );
368         return seg;
369     }
370
371     unsigned long widec = seg->type & _DtCvWIDE_CHAR;
372
373     void* nseg_str;
374     if (widec) {
375         wchar_t* src  = (wchar_t*)seg->handle.string.string + nc;
376         wchar_t* dest = new wchar_t[seg_nc - nc + 1];
377         for (unsigned int i = 0; i < seg_nc - nc; i++)
378             dest[i] = src[i];
379         dest[seg_nc - nc] = '\0';
380         nseg_str = (void*)dest;
381
382         wchar_t* seg_str = (wchar_t*)seg->handle.string.string;
383         seg_str[nc] = '\0'; // chop seg string
384     }
385     else {
386         char* src  = (char*)seg->handle.string.string + nc;
387         char* dest = new char[seg_nc - nc + 1];
388         for (unsigned int i = 0; i < seg_nc - nc; i++)
389             dest[i] = src[i];
390         dest[seg_nc - nc] = '\0';
391         nseg_str = (void*)dest;
392
393         unsigned char* seg_str = (unsigned char*)seg->handle.string.string;
394         seg_str[nc] = '\0'; // chop seg string
395     }
396     DtCvStrVcLenSync(seg);
397
398     unsigned int seg_vcc   = DtCvStrVcc(seg);
399     unsigned int seg_vclen = DtCvStrVcLen(seg);
400
401 #ifdef SYMBOL_HIGHLIGHT
402     _DtCvSegment* symseg = new _DtCvSegment(*seg);
403     symseg->next_seg  = seg->next_seg;
404     symseg->next_disp = seg->next_disp;
405     seg ->next_seg  = symseg;
406     seg ->next_disp = symseg;
407
408     symseg->handle.string.string = new char[2];
409     *(unsigned char*) symseg->handle.string.string      = 0xA4;
410     *((unsigned char*)symseg->handle.string.string + 1) = 0x00;
411     symseg->client_use   = NULL;
412     symseg->internal_use = NULL;
413     symseg->type |=  _DtCvAPP_FLAG1;
414     symseg->type &= ~_DtCvWIDE_CHAR;
415
416     if (symseg->type & _DtCvNEW_LINE) // take _DtCvNEW_LINE over
417         seg->type &= ~_DtCvNEW_LINE;
418
419     symseg->type &=
420                 ~(_DtCvSEARCH_FLAG | _DtCvSEARCH_BEGIN | _DtCvSEARCH_END);
421
422     seg = symseg;
423 #endif
424
425     _DtCvSegment* nseg = new _DtCvSegment(*seg);
426     nseg->next_seg  = seg->next_seg;
427     nseg->next_disp = seg->next_disp;
428     seg ->next_seg  = nseg;
429     seg ->next_disp = nseg;
430
431     if (nseg->type & _DtCvNEW_LINE) // take _DtCvNEW_LINE over
432         seg->type &= ~_DtCvNEW_LINE;
433
434     if (widec)
435         nseg->type |= _DtCvWIDE_CHAR;
436
437     nseg->type &= ~_DtCvAPP_FLAG1;
438
439     nseg->type &= ~(_DtCvSEARCH_FLAG | _DtCvSEARCH_BEGIN | _DtCvSEARCH_END);
440
441     nseg->internal_use = NULL;
442
443     nseg->handle.string.string = nseg_str;
444
445     // set client_use properly
446     nseg->client_use = (_DtCvPointer)new SegClientData(_DtCvSTRING);
447     DtCvStrVcc(nseg, seg_vcc + seg_vclen);
448     DtCvStrVcLenSync(nseg);
449
450     return nseg;
451 }
452
453 // FUNCTION highlight_search_hit
454 // INPUT
455 //   vcc : vcc of the segment to be highlighted
456 //   len : character length of the segment to be highlighted
457 //
458 // RETURN
459 //   the segment to be highlighted
460
461 _DtCvSegment*
462 highlight_search_hit(_DtCvSegment* seg, unsigned int vcc, unsigned int len)
463 {
464     if (seg == NULL || (seg->type & _DtCvPRIMARY_MASK) != _DtCvSTRING)
465         return NULL;
466
467     if (len <= 0)
468         return NULL;
469
470     unsigned int seg_vcc = DtCvStrVcc(seg);
471     unsigned int seg_nc  = DtCvStrLen(seg);
472
473     if (vcc < seg_vcc) // vcc falls short
474         return NULL;
475
476     unsigned long widec = seg->type & _DtCvWIDE_CHAR;
477
478     // translate rel_vcc (vccs) into nseg_nc (characters)
479     unsigned int nseg_nc = DtCvStrVccToIndex(seg, vcc);
480     if (nseg_nc == (unsigned int)-1) // vcc is beyond segment
481         return NULL;
482
483 #ifdef DEBUG
484     fprintf(stderr, "(DEBUG) vcc=%d, index=%d, clen=%d\n", vcc, nseg_nc, len);
485 #endif
486
487     if (len == 0)
488         return NULL;
489     else if (seg_vcc == vcc && seg_nc == len)
490         return seg;
491
492     if (len > seg_nc - nseg_nc) { // len goes beyond this segment
493         if (seg->next_seg == NULL) {
494             len = seg_nc - nseg_nc;
495         }
496         else {
497             _DtCvSegment* sibling = seg->next_seg;
498             unsigned long type = sibling->type & _DtCvPRIMARY_MASK;
499             if (type != _DtCvSTRING || sibling->client_use == NULL ||
500                 DtCvStrVcc(sibling) == (unsigned int)-1 ||
501                 (seg->type & _DtCvWIDE_CHAR) != (sibling->type & _DtCvWIDE_CHAR)) {
502                 len = seg_nc - nseg_nc;
503             }
504             else { // let's merge segments
505                 seg->next_seg  = sibling->next_seg;
506                 seg->next_disp = sibling->next_disp;
507                 sibling->next_seg = NULL;
508                 sibling->next_disp = NULL;
509                 
510                 if (widec) {
511                     wchar_t* src = (wchar_t*)sibling->handle.string.string;
512                     wchar_t* dst = (wchar_t*)seg->handle.string.string;
513                     int slen = wcslen(dst);
514                     int len = wcslen(src);
515                     seg->handle.string.string = (void*)
516                         realloc(seg->handle.string.string,
517                                         sizeof(wchar_t) * (slen + len + 1));
518                     dst = (wchar_t*)seg->handle.string.string;
519                     *((char *) memcpy(dst + slen, src, len) + len) = '\0';
520                 }
521                 else {
522                     char* src = (char*)sibling->handle.string.string;
523                     char* dst = (char*)seg->handle.string.string;
524                     int slen = strlen(dst);
525                     int len = strlen(src);
526                     seg->handle.string.string = (void*)
527                         realloc(seg->handle.string.string, slen + len + 1);
528                     dst = (char*)seg->handle.string.string;
529                     *((char *) memcpy(dst + slen, src, len) + len) = '\0';
530                 }
531                 DtCvStrVcLenSync(seg);
532
533                 if (sibling->handle.string.string)
534                     free (sibling->handle.string.string);
535                 if (sibling->client_use) {
536                     delete (SegClientData*)sibling->client_use;
537                     sibling->client_use = NULL;
538                 }
539
540                 // NOTE: sibling is kept (i.e. not deleted)
541                 // this fact may cause problems in next highlight_search_hit
542
543                 return highlight_search_hit(seg, vcc, len);
544             }
545         }
546     }
547
548     if (nseg_nc) {
549 #ifdef DEBUG    
550         if (widec) {
551             char buf[MB_LEN_MAX + 1];
552             wchar_t* debug_p = (wchar_t*)seg->handle.string.string + nseg_nc;
553             int n = wctomb(buf, *debug_p);
554             assert( n >= 0 );
555             *(buf + n) = '\0';
556             fprintf(stderr, "(DEBUG) initial=%s\n", buf);
557         }
558         else {
559             char* debug_p = (char*)seg->handle.string.string + nseg_nc;
560             fprintf(stderr, "(DEBUG) initial=%c\n", *debug_p);
561         }
562 #endif
563         if ((seg = chop_segment(seg, nseg_nc)) == NULL)
564             return NULL;
565     }
566
567     if (len != seg_nc - nseg_nc)
568         chop_segment(seg, len);
569
570     return seg;
571 }
572
573 static _DtCvSegment *
574 traverse_for_vcc(_DtCvSegment* seg, unsigned int vcc)
575 {
576     if (seg == NULL)
577         return NULL;
578
579     unsigned long seg_ptype = seg->type & _DtCvPRIMARY_MASK;
580
581     if (seg_ptype == _DtCvSTRING && seg->client_use) {
582
583         assert( DtCvStrVcc(seg) <= vcc );
584
585         if (DtCvStrVcc(seg) != (unsigned int)-1) { // check for validity
586             if (vcc < DtCvStrVcc(seg) + DtCvStrVcLen(seg)) // found
587                 return seg;
588         }
589     }
590
591     _DtCvSegment* therein = NULL;
592
593     if (seg_ptype == _DtCvCONTAINER) { // traverse subordinates
594         _DtCvSegment* subordinates;
595         if ((subordinates = seg->handle.container.seg_list) != NULL)
596             therein = traverse_for_vcc(subordinates, vcc);
597     }
598     else if (seg_ptype == _DtCvTABLE) {
599         _DtCvSegment** cell = seg->handle.table.cells;
600         for (; *cell; cell++) {
601             if ((therein = traverse_for_vcc(*cell, vcc)))
602                 break;
603         }
604     }
605     if (therein)
606         return therein;
607
608     // traverse siblings
609     _DtCvSegment* siblings;
610     if ((siblings = seg->next_seg) != NULL)
611         therein = traverse_for_vcc(siblings, vcc);
612
613     return therein;
614 }
615
616 _DtCvSegment*
617 NodeViewInfo::top_container()
618 {
619     if (f_topic == NULL)
620         return NULL;
621
622     // retrieve the top container
623     _DtCvSegment* root_seg;
624     if ((root_seg = f_topic->seg_list) == NULL)
625         return NULL;
626     assert( (root_seg->type & _DtCvPRIMARY_MASK) == _DtCvCONTAINER );
627
628     return root_seg;
629 }
630
631 void
632 clear_search_hits_traverse(_DtCvSegment* seg)
633 {
634     if (seg == NULL)
635         return;
636
637     unsigned long seg_ptype = seg->type & _DtCvPRIMARY_MASK;
638
639     if (seg_ptype == _DtCvSTRING && seg->client_use) {
640         if (seg->type & _DtCvSEARCH_FLAG)
641             seg->type &=
642                 ~(_DtCvSEARCH_FLAG | _DtCvSEARCH_BEGIN | _DtCvSEARCH_END |
643                   _DtCvAPP_FLAG2);
644     }
645
646     if (seg_ptype == _DtCvCONTAINER) { // traverse subordinates
647         _DtCvSegment* subordinates;
648         if ((subordinates = seg->handle.container.seg_list) != NULL)
649             clear_search_hits_traverse(subordinates);
650     }
651     else if (seg_ptype == _DtCvTABLE) {
652         _DtCvSegment** cell = seg->handle.table.cells;
653         for (; *cell; cell++)
654             clear_search_hits_traverse(*cell);
655     }
656
657     // traverse siblings
658     _DtCvSegment* siblings;
659     if ((siblings = seg->next_seg) != NULL)
660         clear_search_hits_traverse(siblings);
661
662     return;
663 }
664
665 void
666 NodeViewInfo::clear_search_hits()
667 {
668     // retrieve the top container
669     _DtCvSegment* root_seg;
670     if ((root_seg = top_container()) == NULL)
671         return;
672
673     clear_search_hits_traverse(root_seg);
674
675     f_hits.clearAndDestroy();
676     f_current_hit = NULL;
677 }
678
679 void
680 NodeViewInfo::set_search_hits(UAS_Pointer<UAS_List<UAS_TextRun> >& hits)
681 {
682     if (f_current_hit) { // clear search hits previously displayed
683         clear_search_hits();
684     }
685
686     // retrieve the top container
687     _DtCvSegment* root_seg;
688     if ((root_seg = top_container()) == NULL)
689         return;
690
691     unsigned int idx;
692
693     for (idx = 0; idx < hits->length(); idx++) { // for each TextRun
694
695         UAS_Pointer<UAS_TextRun>& hit = hits->item(idx);
696
697         _DtCvSegment* seg;
698
699         if ((seg = traverse_for_vcc(root_seg, hit->offset())) == NULL) {
700 #ifdef DEBUG
701             fprintf(stderr, "(DEBUG) traverse_for_vcc failed, offset=%d\n",
702                                                                 hit->offset());
703 #endif
704             continue;
705         }
706 #ifdef DEBUG
707         else
708             fprintf(stderr, "(DEBUG) traverse_for_vcc succeeded, offset=%d\n",
709                                                                 hit->offset());
710 #endif
711
712         assert( (seg->type & _DtCvPRIMARY_MASK) == _DtCvSTRING );
713
714         if ((seg = highlight_search_hit(seg, hit->offset(), hit->length()))) {
715 #ifdef DEBUG
716             fprintf(stderr, "(DEBUG) highlight_search_hit succeeded, "
717                                                 "offset=%d\n", hit->offset());
718 #endif
719             seg->type |=
720                         _DtCvSEARCH_FLAG | _DtCvSEARCH_BEGIN | _DtCvSEARCH_END;
721
722             sr_DtCvSegment* sr_seg = new sr_DtCvSegment(seg);
723
724             if (idx == 0) {
725                 seg->type |= _DtCvAPP_FLAG2;
726                 f_current_hit = sr_seg;
727             }
728             f_hits.append(sr_seg);
729         }
730 #ifdef DEBUG
731         else
732             fprintf(stderr, "(DEBUG) highlight_search_hit failed, offset=%d\n",
733                                                                 hit->offset());
734 #endif
735     }
736 }
737
738 // returns 0 if upon success. returns -1 if it traversal was not changed.
739
740 NodeViewInfo::trav_status_t
741 NodeViewInfo::adjust_current_search_hit(trav_dir_t dir)
742 {
743     trav_status_t status = SUCCESS;
744
745     CC_TPtrDlistIterator<sr_DtCvSegment> iter(f_hits);
746
747     for (++iter; *iter.key() != *f_current_hit;)
748         ++iter;
749
750     if (dir == PREV) {
751         if (*iter.key() != *f_hits.first())
752             --iter;
753     }
754     else {
755         assert( dir == NEXT );
756         if (*iter.key() != *f_hits.last())
757             ++iter;
758     }
759
760     if (*f_current_hit != *iter.key()) {
761         f_current_hit->hitseg->type &= ~_DtCvAPP_FLAG2;
762
763         f_current_hit = iter.key();
764         f_current_hit->hitseg->type |=  _DtCvAPP_FLAG2;
765
766         if (dir == PREV) {
767             if (*f_current_hit == *f_hits.first())
768                 status = REACH_LIMIT;
769         }
770         else
771             if (*f_current_hit == *f_hits.last())
772                 status = REACH_LIMIT;
773     }
774     else
775         status = NOT_MOVED;
776
777     return status;
778 }
779
780 int
781 NodeViewInfo::hit_entries() const
782 {
783     return f_hits.entries();
784 }
785
786 int
787 NodeViewInfo::search_hit_idx()
788 {
789     int i;
790
791     CC_TPtrDlistIterator<sr_DtCvSegment> iter(f_hits);
792
793     for (i = 0, ++iter; *iter.key() != *f_current_hit; i++)
794         ++iter;
795
796     return i;
797 }
798
799 void
800 NodeViewInfo::comp_pixel_values_traverse(_DtCvSegment* seg, Display* dpy,
801                                          Colormap &cmap)
802 {
803     if (seg == NULL)
804         return;
805
806     unsigned long seg_ptype = seg->type & _DtCvPRIMARY_MASK;
807
808     if (seg_ptype == _DtCvSTRING && seg->client_use) {
809         XColor screen, exact;
810         SegClientData* pSCD = (SegClientData*)seg->client_use;
811         assert( pSCD->type() == _DtCvSTRING );
812
813         if (pSCD->bg_color() && pSCD->bg_pixel() == (unsigned long)-1) {
814             UAS_String bg_color = pSCD->bg_color();
815             unsigned long& bg_pixel = f_color_dict[bg_color];
816             if (bg_pixel == (unsigned long)-1) {
817                 if (XAllocNamedColor(dpy, cmap, pSCD->bg_color(),
818                                                         &screen, &exact))
819                     pSCD->bg_pixel(bg_pixel = screen.pixel);
820             }
821             else
822                 pSCD->bg_pixel(bg_pixel);
823         }
824
825         if (pSCD->fg_color() && pSCD->fg_pixel() == (unsigned long)-1) {
826             UAS_String fg_color = pSCD->fg_color();
827             unsigned long& fg_pixel = f_color_dict[fg_color];
828             if (fg_pixel == (unsigned long)-1) {
829                 if (XAllocNamedColor(dpy, cmap, pSCD->fg_color(),
830                                                         &screen, &exact))
831                     pSCD->fg_pixel(fg_pixel = screen.pixel);
832             }
833             else
834                 pSCD->fg_pixel(fg_pixel);
835         }
836     }
837
838     if (seg_ptype == _DtCvCONTAINER) { // traverse subordinates
839         _DtCvSegment* subordinates;
840         if ((subordinates = seg->handle.container.seg_list) != NULL)
841             comp_pixel_values_traverse(subordinates, dpy, cmap);
842     }
843
844     // traverse siblings
845     _DtCvSegment* siblings;
846     if ((siblings = seg->next_seg) != NULL)
847         comp_pixel_values_traverse(siblings, dpy, cmap);
848
849     return;
850 }
851
852 void
853 NodeViewInfo::comp_pixel_values(Display* dpy, Colormap &cmap)
854 {
855     // retrieve the top container
856     _DtCvSegment* root_seg;
857     if ((root_seg = top_container()) == NULL)
858         return;
859
860     comp_pixel_values_traverse(root_seg, dpy, cmap);
861
862 #ifdef CM_DEBUG
863     DictIter<UAS_String, unsigned long> dictiter;
864     for (dictiter = f_color_dict.first(); dictiter() ; dictiter++) {
865         fprintf(stderr, "(DEBUG) color=\"%s\", pixel=0x%lx\n",
866                                 (char*)dictiter.key(), dictiter.value());
867     }
868 #endif
869
870     return;
871 }
872
873 _DtCvSegment*
874 NodeViewInfo::get_segment(unsigned int vcc)
875 {
876   return traverse_for_vcc(top_container(), vcc);
877 }
878
879 unsigned int
880 NodeViewInfo::segment_to_vcc(_DtCvSegment* seg)
881 {
882   return DtCvStrVcc(seg);
883 }
884