00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036 #include <string.h>
00037 #include <stdlib.h>
00038 #include <stdarg.h>
00039
00040 #include "TGHtml.h"
00041 #include "TGButton.h"
00042 #include "TGTextEntry.h"
00043 #include "TGListBox.h"
00044 #include "TGTextEdit.h"
00045 #include "TGComboBox.h"
00046
00047
00048
00049 void TGHtml::UnmapControls()
00050 {
00051
00052
00053 TGHtmlInput *p;
00054
00055 for (p = fFirstInput; p; p = p->fINext) {
00056 if (p->fFrame != 0 ) {
00057 p->fFrame->UnmapWindow();
00058 }
00059 }
00060 }
00061
00062
00063 int TGHtml::MapControls()
00064 {
00065
00066
00067
00068
00069
00070
00071
00072
00073 TGHtmlInput *p;
00074 int x, y, w, h;
00075 int cnt = 0;
00076
00077 x = fVisible.fX;
00078 y = fVisible.fY;
00079 w = fCanvas->GetWidth();
00080 h = fCanvas->GetHeight();
00081 for (p = fFirstInput; p; p = p->fINext) {
00082 if (p->fFrame == 0) continue;
00083 if (p->fY < y + h && p->fY + p->fH > y &&
00084 p->fX < x + w && p->fX + p->fW > x) {
00085
00086 p->fFrame->MoveResize(p->fX - x, p->fY + fFormPadding/2 - y,
00087 p->fW, p->fH - fFormPadding);
00088 p->fFrame->MapWindow();
00089 ++cnt;
00090 } else {
00091
00092 p->fFrame->UnmapWindow();
00093 }
00094 }
00095
00096 return cnt;
00097 }
00098
00099
00100 void TGHtml::DeleteControls()
00101 {
00102
00103
00104
00105 TGHtmlInput *p;
00106
00107 p = fFirstInput;
00108 fFirstInput = 0;
00109 fLastInput = 0;
00110 fNInput = 0;
00111
00112 if (p == 0) return;
00113
00114 for (; p; p = p->fINext) {
00115 if (p->fPForm && ((TGHtmlForm *)p->fPForm)->fHasctl) {
00116 ((TGHtmlForm *)p->fPForm)->fHasctl = 0;
00117 }
00118 if (p->fFrame) {
00119 if (!fExiting) p->fFrame->DestroyWindow();
00120 delete p->fFrame;
00121 p->fFrame = 0;
00122 }
00123 p->fSized = 0;
00124 }
00125 }
00126
00127
00128 static int InputType(TGHtmlElement *p)
00129 {
00130
00131
00132 int type = INPUT_TYPE_Unknown;
00133 const char *z;
00134 int i;
00135 static struct {
00136 const char *zName;
00137 int type;
00138 } types[] = {
00139 { "checkbox", INPUT_TYPE_Checkbox },
00140 { "file", INPUT_TYPE_File },
00141 { "hidden", INPUT_TYPE_Hidden },
00142 { "image", INPUT_TYPE_Image },
00143 { "password", INPUT_TYPE_Password },
00144 { "radio", INPUT_TYPE_Radio },
00145 { "reset", INPUT_TYPE_Reset },
00146 { "submit", INPUT_TYPE_Submit },
00147 { "text", INPUT_TYPE_Text },
00148 { "name", INPUT_TYPE_Text },
00149 { "textfield", INPUT_TYPE_Text },
00150 { "button", INPUT_TYPE_Button },
00151 { "name", INPUT_TYPE_Text },
00152 };
00153
00154 switch (p->fType) {
00155 case Html_INPUT:
00156 z = p->MarkupArg("type", "text");
00157 if (z == 0) break;
00158 for (i = 0; i < int(sizeof(types) / sizeof(types[0])); i++) {
00159 if (strcasecmp(types[i].zName, z) == 0) {
00160 type = types[i].type;
00161 break;
00162 }
00163 }
00164 break;
00165
00166 case Html_SELECT:
00167 type = INPUT_TYPE_Select;
00168 break;
00169
00170 case Html_TEXTAREA:
00171 type = INPUT_TYPE_TextArea;
00172 break;
00173
00174 case Html_APPLET:
00175 case Html_IFRAME:
00176 case Html_EMBED:
00177 type = INPUT_TYPE_Applet;
00178 break;
00179
00180 default:
00181 CANT_HAPPEN;
00182 break;
00183 }
00184 return type;
00185 }
00186
00187
00188 void TGHtml::SizeAndLink(TGFrame *frame, TGHtmlInput *pElem)
00189 {
00190
00191
00192
00193
00194
00195 pElem->fFrame = frame;
00196 if (pElem->fFrame == 0) {
00197 pElem->Empty();
00198 } else if (pElem->fItype == INPUT_TYPE_Hidden) {
00199 pElem->fW = 0;
00200 pElem->fH = 0;
00201 pElem->fFlags &= ~HTML_Visible;
00202 pElem->fStyle.fFlags |= STY_Invisible;
00203 } else {
00204 pElem->fW = frame->GetDefaultWidth();
00205 pElem->fH = frame->GetDefaultHeight() + fFormPadding;
00206 pElem->fFlags |= HTML_Visible;
00207 pElem->fHtml = this;
00208 }
00209 pElem->fINext = 0;
00210 if (fFirstInput == 0) {
00211 fFirstInput = pElem;
00212 } else {
00213 fLastInput->fINext = pElem;
00214 }
00215 fLastInput = pElem;
00216 pElem->fSized = 1;
00217
00218 #if 0
00219 if (pElem->fFrame) {
00220 pElem->fFrame->ChangeOptions(pElem->fFrame->GetOptions() | kOwnBackground);
00221 pElem->fFrame->SetBackgroundColor(_defaultFrameBackground);
00222 }
00223 #else
00224 if (pElem->fFrame) {
00225 int bg = pElem->fStyle.fBgcolor;
00226
00227 ColorStruct_t *cbg = fApColor[bg];
00228
00229 pElem->fFrame->ChangeOptions(pElem->fFrame->GetOptions() | kOwnBackground);
00230 pElem->fFrame->SetBackgroundColor(cbg->fPixel);
00231 }
00232 #endif
00233
00234 if (pElem->fFrame) {
00235
00236
00237 pElem->fFrame->MapSubwindows();
00238 pElem->fFrame->Layout();
00239 }
00240 }
00241
00242
00243 void TGHtml::AppendText(TGString *str, TGHtmlElement *pFirs,
00244 TGHtmlElement *pEnd)
00245 {
00246
00247
00248
00249 while (pFirs && pFirs != pEnd) {
00250 switch (pFirs->fType) {
00251 case Html_Text:
00252 str->Append(((TGHtmlTextElement *)pFirs)->fZText);
00253 break;
00254
00255 case Html_Space:
00256 if (pFirs->fFlags & HTML_NewLine) {
00257 str->Append("\n");
00258 } else {
00259 int cnt;
00260 static char zSpaces[] = " ";
00261 cnt = pFirs->fCount;
00262 while (cnt > (int)sizeof(zSpaces) - 1) {
00263 str->Append(zSpaces, sizeof(zSpaces) - 1);
00264 cnt -= sizeof(zSpaces) - 1;
00265 }
00266 if (cnt > 0) {
00267 str->Append(zSpaces, cnt);
00268 }
00269 }
00270 break;
00271
00272 default:
00273 break;
00274 }
00275 pFirs = pFirs->fPNext;
00276 }
00277 }
00278
00279
00280 class TGHtmlLBEntry : public TGTextLBEntry {
00281 public:
00282 TGHtmlLBEntry(const TGWindow *p, TGString *s, TGString *val, int ID) :
00283 TGTextLBEntry(p, s, ID) { fVal = val; }
00284 virtual ~TGHtmlLBEntry() { if (fVal) delete fVal; }
00285
00286 const char *GetValue() const { return fVal ? fVal->GetString() : 0; }
00287
00288 protected:
00289 TGString *fVal;
00290 };
00291
00292
00293
00294 void TGHtml::AddSelectOptions(TGListBox *lb, TGHtmlElement *p,
00295 TGHtmlElement *pEnd)
00296 {
00297
00298
00299
00300
00301
00302
00303
00304
00305
00306 int id = 0;
00307
00308 while (p && p != pEnd && p->fType != Html_EndSELECT) {
00309 if (p->fType == Html_OPTION) {
00310 TGString *str;
00311 int selected = -1;
00312
00313 const char *zValue = p->MarkupArg("value", "");
00314 const char *sel = p->MarkupArg("selected", "");
00315 if (sel && !strcmp(sel, "selected"))
00316 selected = id;
00317
00318 p = p->fPNext;
00319
00320 str = new TGString("");
00321 while (p && p != pEnd &&
00322 p->fType != Html_EndOPTION &&
00323 p->fType != Html_OPTION &&
00324 p->fType != Html_EndSELECT) {
00325 if (p->fType == Html_Text) {
00326 str->Append(((TGHtmlTextElement *)p)->fZText);
00327 } else if (p->fType == Html_Space) {
00328 str->Append(" ");
00329 }
00330 p = p->fPNext;
00331 }
00332 lb->AddEntry(new TGHtmlLBEntry(lb->GetContainer(), str,
00333 new TGString(zValue), id),
00334 new TGLayoutHints(kLHintsTop | kLHintsExpandX));
00335
00336 if (selected >= 0)
00337 lb->Select(selected);
00338 ++id;
00339 } else {
00340 p = p->fPNext;
00341 }
00342 }
00343 }
00344
00345
00346 int TGHtml::ControlSize(TGHtmlInput *pElem)
00347 {
00348
00349
00350
00351
00352
00353
00354
00355
00356
00357
00358
00359 int incomplete = 0;
00360
00361 if (pElem->fSized) return 0;
00362
00363 pElem->fItype = InputType(pElem);
00364
00365
00366
00367
00368
00369
00370
00371 switch (pElem->fItype) {
00372 case INPUT_TYPE_File:
00373 case INPUT_TYPE_Hidden:
00374 case INPUT_TYPE_Image:
00375 pElem->Empty();
00376 SizeAndLink(0, pElem);
00377 break;
00378
00379 case INPUT_TYPE_Checkbox: {
00380 pElem->fCnt = ++fNInput;
00381 TGCheckButton *f = new TGCheckButton(fCanvas, "", pElem->fCnt);
00382 if (pElem->MarkupArg("checked", 0))
00383 ((TGCheckButton *)f)->SetState(kButtonDown);
00384 f->Associate(this);
00385 f->Resize(f->GetDefaultSize());
00386 SizeAndLink(f, pElem);
00387 break;
00388 }
00389
00390 case INPUT_TYPE_Radio: {
00391 pElem->fCnt = ++fNInput;
00392 TGRadioButton *f = new TGRadioButton(fCanvas, "", pElem->fCnt);
00393 if (pElem->MarkupArg("checked", 0))
00394 ((TGRadioButton *)f)->SetState(kButtonDown);
00395 f->Associate(this);
00396 f->Resize(f->GetDefaultSize());
00397 SizeAndLink(f, pElem);
00398 break;
00399 }
00400
00401 case INPUT_TYPE_Reset: {
00402 pElem->fCnt = ++fNInput;
00403 const char *z = pElem->MarkupArg("value", 0);
00404 if (!z) z = "Reset";
00405 TGTextButton *f = new TGTextButton(fCanvas, new TGHotString(z), pElem->fCnt);
00406 f->RequestFocus();
00407 f->Associate(this);
00408 f->Resize(f->GetDefaultSize());
00409 SizeAndLink(f, pElem);
00410 break;
00411 }
00412
00413 case INPUT_TYPE_Button:
00414 case INPUT_TYPE_Submit: {
00415 pElem->fCnt = ++fNInput;
00416 const char *z = pElem->MarkupArg("value", 0);
00417 if (!z) z = "Submit";
00418 TGTextButton *f = new TGTextButton(fCanvas, new TGHotString(z), pElem->fCnt);
00419 f->RequestFocus();
00420 f->Associate(this);
00421
00422 f->Resize(f->GetDefaultSize());
00423 SizeAndLink(f, pElem);
00424 break;
00425 }
00426
00427 case INPUT_TYPE_Text: {
00428 pElem->fCnt = ++fNInput;
00429 const char *z = pElem->MarkupArg("maxlength", 0);
00430 int maxlen = z ? atoi(z) : 256;
00431 if (maxlen < 2) maxlen = 2;
00432 z = pElem->MarkupArg("size", 0);
00433 int size = z ? atoi(z) * 5 : 150;
00434 TGTextEntry *f = new TGTextEntry(fCanvas, new TGTextBuffer(maxlen),
00435 pElem->fCnt);
00436 z = pElem->MarkupArg("value", 0);
00437 if (z) f->AppendText(z);
00438 f->Resize(size, f->GetDefaultHeight());
00439 SizeAndLink(f, pElem);
00440 break;
00441 }
00442
00443 case INPUT_TYPE_Password: {
00444 pElem->fCnt = ++fNInput;
00445 const char *z = pElem->MarkupArg("maxlength", 0);
00446 int maxlen = z ? atoi(z) : 256;
00447 if (maxlen < 2) maxlen = 2;
00448 z = pElem->MarkupArg("size", 0);
00449 int size = z ? atoi(z) * 5 : 150;
00450 TGTextEntry *f = new TGTextEntry(fCanvas, new TGTextBuffer(maxlen),
00451 pElem->fCnt);
00452 f->SetEchoMode(TGTextEntry::kPassword);
00453 z = pElem->MarkupArg("value", 0);
00454 if (z) f->AppendText(z);
00455 f->Resize(size, f->GetDefaultHeight());
00456 SizeAndLink(f, pElem);
00457 break;
00458 }
00459
00460 case INPUT_TYPE_Select: {
00461 pElem->fCnt = ++fNInput;
00462 const char *z = pElem->MarkupArg("size", 0);
00463 int size = z ? atoi(z) : 1;
00464 UInt_t width = 0, height = 0;
00465 if (size == 1) {
00466 TGComboBox *cb = new TGComboBox(fCanvas, pElem->fCnt);
00467 TGListBox *lb = cb->GetListBox();
00468 AddSelectOptions(lb, pElem, pElem->fPEnd);
00469 TGLBEntry *e = lb->GetSelectedEntry();
00470 if (e) lb->Select(e->EntryId(), kFALSE);
00471 lb->MapSubwindows();
00472 lb->Layout();
00473 for (int i=0;i<lb->GetNumberOfEntries();++i) {
00474 TGHtmlLBEntry *te = (TGHtmlLBEntry *)lb->GetEntry(i);
00475 if (te && te->GetText())
00476 width = TMath::Max(width, te->GetDefaultWidth());
00477 }
00478 height = lb->GetItemVsize() ? lb->GetItemVsize()+4 : 22;
00479 cb->Resize(width > 0 ? width+30 : 200,
00480 height > 22 ? height : 22);
00481 if (e) cb->Select(e->EntryId(), kFALSE);
00482 SizeAndLink(cb, pElem);
00483 } else {
00484 TGListBox *lb = new TGListBox(fCanvas, pElem->fCnt);
00485 z = pElem->MarkupArg("multiple", 0);
00486 if (z) lb->SetMultipleSelections(kTRUE);
00487 AddSelectOptions(lb, pElem, pElem->fPEnd);
00488 for (int i=0;i<lb->GetNumberOfEntries();++i) {
00489 TGHtmlLBEntry *te = (TGHtmlLBEntry *)lb->GetEntry(i);
00490 if (te && te->GetText())
00491 width = TMath::Max(width, te->GetDefaultWidth());
00492 }
00493 height = lb->GetItemVsize() ? lb->GetItemVsize() : 22;
00494 lb->Resize(width > 0 ? width+30 : 200, height * size);
00495 lb->Associate(this);
00496 SizeAndLink(lb, pElem);
00497 }
00498 break;
00499 }
00500
00501 case INPUT_TYPE_TextArea: {
00502 pElem->fCnt = ++fNInput;
00503 const char *z = pElem->MarkupArg("rows", 0);
00504
00505 z = pElem->MarkupArg("cols", 0);
00506
00507 TGTextEdit *f = new TGTextEdit(fCanvas, 300, 200, pElem->fCnt);
00508 TGString str("");
00509 AppendText(&str, pElem, pElem->fPEnd);
00510
00511 SizeAndLink(f, pElem);
00512 break;
00513 }
00514
00515 case INPUT_TYPE_Applet: {
00516
00517
00518 TGFrame *f = ProcessApplet(pElem);
00519 if (!f) {
00520 pElem->Empty();
00521 break;
00522 }
00523 pElem->fCnt = ++fNInput;
00524 SizeAndLink(f, pElem);
00525 break;
00526 }
00527
00528 default: {
00529 CANT_HAPPEN;
00530 pElem->fFlags &= ~HTML_Visible;
00531 pElem->fStyle.fFlags |= STY_Invisible;
00532 pElem->fFrame = 0;
00533 break;
00534 }
00535 }
00536 return incomplete;
00537 }
00538
00539
00540 int TGHtml::FormCount(TGHtmlInput *p, int radio)
00541 {
00542
00543
00544 TGHtmlElement *q = p;
00545
00546 switch (p->fType) {
00547 case Html_SELECT:
00548 return p->fSubId;
00549 case Html_TEXTAREA:
00550 case Html_INPUT:
00551 if (radio && p->fType == INPUT_TYPE_Radio)
00552 return p->fSubId;
00553 return ((TGHtmlForm *)p->fPForm)->fElements;
00554 case Html_OPTION:
00555 while ((q = q->fPPrev))
00556 if (q->fType == Html_SELECT) return ((TGHtmlInput *)q)->fSubId;
00557 }
00558 return -1;
00559 }
00560
00561
00562 void TGHtml::AddFormInfo(TGHtmlElement *p)
00563 {
00564
00565
00566 TGHtmlElement *q;
00567 TGHtmlForm *f;
00568 const char *name, *z;
00569 int t;
00570
00571 switch (p->fType) {
00572 case Html_SELECT:
00573 case Html_TEXTAREA:
00574 case Html_INPUT: {
00575 TGHtmlInput *input = (TGHtmlInput *) p;
00576 if (!(f = fFormStart)) return;
00577 input->fPForm = fFormStart;
00578 if (!f->fPFirst)
00579 f->fPFirst = p;
00580 if (fFormElemLast)
00581 fFormElemLast->fINext = input;
00582 fFormElemLast = input;
00583 input->fInpId = fInputIdx++;
00584 t = input->fItype = InputType(input);
00585 if (t == INPUT_TYPE_Radio) {
00586 if ((name = p->MarkupArg("name", 0))) {
00587 for (q = f->fPFirst; q; q = ((TGHtmlInput *)q)->fINext) {
00588 if ((z = q->MarkupArg("name", 0)) && !strcmp(z, name)) {
00589 input->fSubId = fRadioIdx++;
00590 break;
00591 }
00592 }
00593 if (!q) input->fSubId = fRadioIdx = 0;
00594 }
00595 }
00596 break;
00597 }
00598
00599 case Html_FORM:
00600 fFormStart = (TGHtmlForm *) p;
00601 ((TGHtmlForm *)p)->fFormId = fNForm++;
00602 break;
00603
00604 case Html_EndTEXTAREA:
00605 case Html_EndSELECT:
00606 case Html_EndFORM:
00607 fFormStart = 0;
00608 fInputIdx = 0;
00609 fRadioIdx = 0;
00610 fFormElemLast = 0;
00611 break;
00612
00613 case Html_OPTION:
00614 if (fFormElemLast && fFormElemLast->fType == Html_SELECT)
00615 fFormElemLast->fSubId++;
00616 break;
00617
00618 default:
00619 break;
00620 }
00621 }
00622
00623
00624
00625
00626 static char gNeedEscape[] = {
00627 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
00628 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
00629 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0,
00630 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1,
00631 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
00632 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0,
00633 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
00634 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1,
00635 };
00636 #define NeedToEscape(C) ((C)>0 && (C)<127 && gNeedEscape[(int)(C)])
00637
00638
00639 void TGHtml::EncodeText(TGString *str, const char *z)
00640 {
00641
00642
00643 int i;
00644
00645 while (*z) {
00646 for (i = 0; z[i] && !NeedToEscape(z[i]); ++i) {}
00647 if (i > 0) str->Append(z, i);
00648 z += i;
00649 while (*z && NeedToEscape(*z)) {
00650 if (*z == ' ') {
00651 str->Append("+", 1);
00652 } else if (*z == '\n') {
00653 str->Append("%0D%0A", 6);
00654 } else if (*z == '\r') {
00655
00656 } else {
00657 char zBuf[10];
00658 snprintf(zBuf, 10, "%%%02X", 0xff & *z);
00659 str->Append(zBuf, 3);
00660 }
00661 z++;
00662 }
00663 }
00664 }
00665
00666
00667 Bool_t TGHtml::ProcessMessage(Long_t msg, Long_t p1, Long_t p2)
00668 {
00669
00670
00671
00672
00673
00674
00675
00676
00677
00678
00679
00680
00681
00682
00683
00684
00685
00686
00687
00688
00689
00690
00691
00692
00693
00694
00695
00696
00697
00698
00699
00700
00701
00702
00703
00704
00705
00706
00707
00708
00709
00710
00711
00712
00713
00714
00715
00716
00717
00718
00719
00720
00721
00722
00723
00724
00725
00726
00727
00728
00729
00730
00731
00732
00733
00734
00735
00736
00737
00738
00739
00740
00741
00742
00743
00744
00745
00746
00747
00748
00749
00750
00751
00752
00753
00754
00755
00756
00757
00758
00759
00760
00761
00762
00763
00764
00765
00766
00767
00768
00769 return TGView::ProcessMessage(msg, p1, p2);
00770 }