1 #include "HelpViewer.h"
2
3 #define IMAGECLASS HelpImg
4 #define IMAGEFILE <HelpViewer/HelpViewer.iml>
5 #include <Draw/iml_source.h>
6
7 const char *TOPICLINK = "^topic`:`/`/";
8
HelpViewer()9 HelpViewer::HelpViewer()
10 {
11 // adds toolbar
12 AddFrame(toolBar);
13
14 // setups splitter and its contents
15 Add(splitter);
16 splitter.Horz(tocPane, contentsPane).SetPos(2500);
17 contentsPane.AutoHideSb();
18 contentsPane.SetZoom(Zoom(1,1));
19 contentsPane.HMargins(20);
20
21 tocPane.Add(mainTocTree.NoRoot().SizePos());
22
23 // setup TOC link callback
24 mainTocTree.WhenSel = THISBACK(tocLinkCb);
25 contentsPane.WhenLink << THISBACK(contentLinkCb);
26
27 // initialize link stack
28 stack.Clear();
29 tos = -1;
30
31 Sizeable().Zoomable();
32
33 // loads toolbar
34 toolBar.Set(THISBACK(toolBarCb));
35 }
36
37 // appends a treeCtrl to main tocCtrl
AppendTOC(TreeCtrl const & t,int curId,int destId)38 void HelpViewer::AppendTOC(TreeCtrl const &t, int curId, int destId)
39 {
40 // adds root node of current level
41 int destChild = mainTocTree.Add(destId, t.GetNode(curId));
42
43 // recursively add all children
44 for(int i = 0; i < t.GetChildCount(curId); i++)
45 AppendTOC(t, t.GetChild(curId, i), destChild);
46 }
47
48 // Parses TOC and fills tocTree control
LoadTOC(String const & tocLink)49 bool HelpViewer::LoadTOC(String const &tocLink)
50 {
51 // TOC is composed by QTF lines with a TOC link and label text
52 // lines not containing the TOC link are simply ignored
53 // TOC level is represented by number of TABS contained
54 // inside a line; zero tabs means toplevel, id 0 of tocTree
55 Vector<int>ids;
56 ids.Add(0);
57 int curLevel = 0;
58 int curId = 0;
59 TreeCtrl tocTree;
60
61 Topic t = GetTopic(tocLink);
62 if(IsNull(t.text))
63 return false;
64
65 String label = t.label;
66 String topic = t.link;
67
68 // sets toc root string from topic ticle
69 tocTree.SetRoot(Null, t.title);
70
71 // converts QTF to RichTxt, easier to analyze
72 RichText txt = ParseQTF(t.text);
73
74 // extract all paragraphs from RichTxt, skip other objects
75 for(int iPart = 0; iPart < txt.GetPartCount(); iPart++)
76 {
77 String tocLine;
78 String lineLink;
79 if(!txt.IsPara(iPart))
80 continue;
81 RichPara p = txt.Get(iPart);
82 for(int iParaPart = 0; iParaPart < p.GetCount(); iParaPart++)
83 {
84 RichPara::Part ¶Part = p.part[iParaPart];
85 if(paraPart.format.link != "")
86 lineLink = paraPart.format.link;
87 if(paraPart.NonText())
88 continue;
89 tocLine += paraPart.text.ToString();
90 }
91 // if part contains no text nor link to topic stuffs, simply skip it
92 if(tocLine == "" || lineLink == "" || !lineLink.StartsWith("topic:"))
93 continue;
94
95 // now we should count tabls to get TOC indent level
96 int level = 0;
97 int j;
98 while( (j = tocLine.Find(0x09)) >= 0)
99 {
100 level++;
101 tocLine.Remove(j);
102 }
103 // allows just SINGLE UPPER level change, i.e., deeper ONE level from current
104 // for each step; backleveling is possible at any depth
105 if(level > curLevel+1)
106 return false;
107 if(level > curLevel)
108 {
109 ids.Add(curId);
110 curLevel++;
111 }
112 else while(curLevel > level)
113 {
114 curLevel--;
115 ids.Pop();
116 }
117
118 // add the line to correct tree node
119 curId = tocTree.Add(ids.Top(), Null, Value(lineLink), Value(tocLine));
120 }
121
122 // if the tree control is non empty, appends it to the main TOC TreeCtrl
123 if(tocTree.GetChildCount(0))
124 AppendTOC(tocTree);
125
126
127 // opens all content tree and display first item
128 mainTocTree.OpenDeep(0);
129 mainTocTree.SetCursor(2);
130
131 // stores first topic at top of stack
132 String curLink = mainTocTree.Get();
133 stack.Clear();
134 stack.Add(curLink);
135 tos = 0;
136
137 return true;
138 }
139
140 // go to a selected link
showLink(String const & link)141 void HelpViewer::showLink(String const &link)
142 {
143 Topic t = GetTopic(link);
144 if(!IsNull(t.text))
145 {
146 Zoom zoom;
147 zoom.m = 160;
148 zoom.d = 1000;
149
150 String label = t.label;
151 RichText txt = ParseQTF(t.text);
152 contentsPane.Pick(pick(txt), zoom);
153 contentsPane.GotoLabel(label, true);
154 int tocId = mainTocTree.Find(link);
155 if(tocId >= 0)
156 {
157 // disable tocTree action on selecting cursor
158 // otherwise we've got a recursive call
159 mainTocTree.WhenSel.Clear();
160 mainTocTree.SetCursor(tocId);
161
162 // re-enable tocTree action
163 mainTocTree.WhenSel = THISBACK(tocLinkCb);
164
165 // setup window title
166 Title(mainTocTree.GetValue());
167 }
168 }
169 }
170
171 // reacts on link selection inside content pane
contentLinkCb(String const & link)172 void HelpViewer::contentLinkCb(String const &link)
173 {
174 // clear forward buffer
175 stack.Trim(tos+1);
176
177 // updates history
178 int tocId = mainTocTree.GetCursor();
179 if(tocId > 0)
180 {
181 String curLink = mainTocTree.Get();
182 stack.Add(curLink);
183 tos++;
184 toolBar.Set(THISBACK(toolBarCb));
185
186 }
187
188 // shows link inside main pane
189 showLink(link);
190 }
191
192
tocLinkCb()193 void HelpViewer::tocLinkCb()
194 {
195 int id = mainTocTree.GetCursor();
196 if(id < 0)
197 return;
198
199 // gets link
200 String link = mainTocTree.Get(id);
201
202 // follow link
203 contentLinkCb(link);
204 }
205
206 // go previous/next
backCb(void)207 void HelpViewer::backCb(void)
208 {
209 if(--tos >= 0)
210 {
211 String link = stack[tos];
212 showLink(link);
213 }
214 toolBar.Set(THISBACK(toolBarCb));
215 }
216
fwCb(void)217 void HelpViewer::fwCb(void)
218 {
219 if(tos < stack.GetCount() - 1)
220 {
221 String link = stack[++tos];
222 showLink(link);
223 }
224 toolBar.Set(THISBACK(toolBarCb));
225 }
226
227 // toolbar construction
toolBarCb(Bar & bar)228 void HelpViewer::toolBarCb(Bar &bar)
229 {
230 bar.Add(tos > 0, "Back", HelpImg::Back(), THISBACK(backCb));
231 bar.Add(tos < stack.GetCount() - 1, "Forward", HelpImg::Forward(), THISBACK(fwCb));
232 }
233