#include "TCtrlLibHelp.h" #pragma hdrstop #pragma BLITZ_APPROVE #include NAMESPACE_UPP #define LAYOUTFILE #include #define IMAGEFILE #define IMAGECLASS DlgHelpViewImg #include class ReportPageDraw : public PageDraw { public: ReportPageDraw(Size page_size); void Write(DocReport& output); virtual Draw& Info() { return Page(0); } virtual Draw& Page(int i); private: Array pages; Size page_size; }; ReportPageDraw::ReportPageDraw(Size page_size) : page_size(page_size) { Page(0); } Draw& ReportPageDraw::Page(int i) { while(pages.GetCount() <= i) pages.Add().Create(page_size); return pages[i]; } void ReportPageDraw::Write(DocReport& report) { for(int i = 0; i < pages.GetCount(); i++) { if(i) report.NextPage(); report.DrawDrawing(Rect(page_size), pages[i]); } } /* const Color *ThickWhiteBorder[] = { (Color *)4, &SWhite, &SWhite, &SWhite, &SWhite, &SWhite, &SWhite, &SWhite, &SWhite, &SWhite, &SWhite, &SWhite, &SWhite, &SWhite, &SWhite, &SWhite, &SWhite, }; GLOBAL_VARP(BorderFrame, ThickWhiteFrame, (ThickWhiteBorder)); */ INITBLOCK { RegisterHelpStdItems(); } class DlgHelpTopicTab : public WithHelpTopicTabLayout { public: typedef DlgHelpTopicTab CLASSNAME; DlgHelpTopicTab(); String Run(String init, bool index); virtual bool HotKey(dword key); private: void OnLink(const String& link); void OnOK(); void OnTab(); void OnSearch(); private: enum { TOC_TAB, INDEX_TAB, TOPICS_TAB }; WithHelpTopicIndexLayout index_page; RichTextView toc_page; RichTextView topics_page; String selection; Array entries; bool toc_inited; bool topics_inited; }; String RunDlgHelpTopicIndex(String init, bool index) { return DlgHelpTopicTab().Run(init, index); } void OpenHelpTopicIndex(String topic, bool index) { String s = RunDlgHelpTopicIndex(topic, index); if(!IsNull(s)) RunDlgHelpTopic(s); } //RegisterHelpTopicObjectTitle(DlgHelpTopicTab, t_("Nápověda")) DlgHelpTopicTab::DlgHelpTopicTab() { toc_inited = topics_inited = false; CtrlLayoutOKCancel(*this, t_("Help system")); HelpTopic("topic://TCtrlLib/DlgHelpTopicTab"); Sizeable().Zoomable(); CtrlLayout(index_page); ASSERT(tab.GetCount() == TOC_TAB); tab.Add(toc_page.HSizePos(4, 4).VSizePos(4, 4), t_("Contents")); ASSERT(tab.GetCount() == INDEX_TAB); tab.Add(index_page.HSizePos(4, 4).VSizePos(4, 4), t_("Index")); ASSERT(tab.GetCount() == TOPICS_TAB); tab.Add(topics_page.HSizePos(4, 4).VSizePos(4, 4), t_("All topics")); tab <<= THISBACK(OnTab); toc_page.Margins(4); toc_page.SetZoom(Zoom(180, 1024)); toc_page.WhenLink = THISBACK(OnLink); topics_page.Margins(4); topics_page.SetZoom(Zoom(180, 1024)); topics_page.WhenLink = THISBACK(OnLink); index_page.search <<= THISBACK(OnSearch); // index_page.list.AutoHideSb().NoHeader().NoGrid(); index_page.list.AddIndex(); index_page.list.AddColumn().SetDisplay(RichTextDisplay()); ok <<= index_page.list.WhenLeftDouble = THISBACK(OnOK); } String DlgHelpTopicTab::Run(String init, bool index) { tab <<= (index ? INDEX_TAB : TOC_TAB); OnTab(); if(TopWindow::Run() != IDOK) return Null; return selection; } void DlgHelpTopicTab::OnLink(const String& link) { selection = link; AcceptBreak(IDOK); } //RegisterHelpTopicObjectTitle(DlgHelpTopicSelect, t_("Výběr tématu nápovědy")) void DlgHelpTopicTab::OnOK() { if(tab.Get() == INDEX_TAB && index_page.list.IsCursor()) { selection = index_page.list.Get(0); if(*selection == '!') selection.Remove(0); if(selection.Find(';') >= 0) { // select topic WithHelpTopicSelectLayout dlg; CtrlLayoutOKCancel(dlg, t_("Help topic selection")); dlg.list.AddIndex(); dlg.list.AddColumn().SetDisplay(RichTextDisplay()); dlg.list.WhenLeftDouble = dlg.Acceptor(IDOK); const char *p = selection; while(*p) { while(*p == '!' || *p == ' ') p++; const char *b = p; while(*p && *p != ';') p++; if(p > b) { String key(b, p); dlg.list.Add(key, HelpTopicGet(key).GetTitle()); } if(*p) p++; } if(dlg.list.GetCount() == 0) { Exclamation(NFormat(t_("Invalid help topic [* \1%s\1]."), selection)); return; } dlg.list.SetCursor(0); if(dlg.list.GetCount() > 1 && dlg.Run() != IDOK) return; selection = dlg.list.Get(0); } AcceptBreak(IDOK); } } void DlgHelpTopicTab::OnTab() { switch(tab.Get()) { case TOC_TAB: { if(!toc_inited) { toc_inited = true; RichText toc; HelpTopicOnlineToc()(toc); toc_page.Pick(toc); } break; } case TOPICS_TAB: { if(!topics_inited) { topics_inited = true; RichText topics; String lang = LNGAsText(GetCurrentLanguage()); if(lang.GetLength() > 5) lang.Trim(5); String fend; fend << '$' << ToLower(lang); VectorMap dummy; Vector order = GetSortOrder(TopicBase().GetKeys(), GetLanguageInfo()); for(int po = 0; po < order.GetCount(); po++) { int p = order[po]; String package = TopicBase().GetKey(p); if(TopicBase()[p].Find("appdoc") >= 0) { bool first = true; const Vector& group = TopicBase()[p].Get("appdoc"); Vector gorder = GetSortOrder(group, GetLanguageInfo()); for(int io = 0; io < gorder.GetCount(); io++) { int i = gorder[io]; String t = group[i]; String topic; topic << "topic://" << package << "/appdoc/" << t; int l = t.Find('$'); if(l >= 0 && t.Mid(l) == fend) { if(first) { RichPara head; head.format.before = 100; head.Cat(package, head.format); topics.Cat(head); first = false; } RichPara para; para.format.lm = 150; para.format.link = topic; para.Cat(t.Left(l), para.format); topics.Cat(para); } } } } topics_page.Pick(topics); } break; } case INDEX_TAB: { if(entries.IsEmpty()) { index_page.list.Clear(); entries = HelpTopicFormatIndex(); for(int i = 0; i < entries.GetCount(); i++) if(entries[i].nesting >= 0) { WString s; s.Cat('_', entries[i].nesting * 3); s.Cat(entries[i].text); index_page.list.Add(entries[i].topics, s); } else entries.Remove(i--); } break; } } } static bool LessEntry(const HelpIndexFormattedEntry& entry, const WString& s) { return GetLanguageInfo().Compare(FromUnicode(MQTFStrip(entry.full_text)), FromUnicode(s)) < 0; } void DlgHelpTopicTab::OnSearch() { WString text = ~index_page.search; int n = BinFindIndex(entries, index_page.search.GetText(), &LessEntry); if(n < index_page.list.GetCount()) index_page.list.SetCursor(n); } bool DlgHelpTopicTab::HotKey(dword key) { if(key >= ' ' && key <= 255 || key == K_BACKSPACE || key == K_LEFT || key == K_RIGHT || key == K_HOME || key == K_END) { int l = index_page.search.GetLength(), h = l; index_page.search.GetSelection(l, h); index_page.search.SetFocus(); index_page.search.SetSelection(l, h); return index_page.search.Key(key, 1); } return TopWindow::HotKey(key); } GLOBAL_VAR(Callback1, HelpTopicBookMenu) GLOBAL_VAR(Callback1, HelpTopicOnlineToc) class DlgHelpTopic : public TopWindow { public: typedef DlgHelpTopic CLASSNAME; DlgHelpTopic(); static ConfigItem& config(); virtual void Serialize(Stream& stream); void Run(String topic); virtual void Activate(); private: void OnLink(const String& link); bool OpenPage(String page, int y = 0); void Rescan() { toolbar.Set(THISBACK(ToolMain)); } TOOL(Main) TOOL(Zoom) TOOL(Back) TOOL(Forward) TOOL(Index) TOOL(Print) // TOOL(BookMenu) // TOOL(Book) // TOOL(BookPDF) // TOOL(BookRTF) void AddRecent(String page, int y); void SeekAnchor(const char *anchor); void SyncPage(WString title, String text /*, String style*/); private: ToolBar toolbar; RichTextView viewer; // QtfCtrl qtf; StatusBar statusbar; // SliderCtrl zoom; // Point book_menu_pos; // int help_topic_seq; // const HelpPage *current_page; String current_topic; WString title; String topic_qtf; // String style_qtf; static Vector recent_pages; static Vector recent_y; static int recent_pos; static int recent_zoom; enum { MAX_RECENT = 100 }; }; Vector DlgHelpTopic::recent_pages; Vector DlgHelpTopic::recent_y; int DlgHelpTopic::recent_pos = 0; int DlgHelpTopic::recent_zoom = DOC_SCREEN_ZOOM; void RunDlgHelpTopic(String topic) { DlgHelpTopic().Run(topic); } DlgHelpTopic::DlgHelpTopic() //: current_page(0) { // help_topic_seq = 0; Title(t_("Help viewer")); MaximizeBox().Sizeable(); // zoom.SetRect(0, 0, 60, 16); // zoom.MinMax(100, 300).Step(10); // zoom <<= THISBACK(OnZoom); // zoom <<= recent_zoom; // dialog.WhenClose = dialog.Breaker(IDCANCEL); // TopWindow WhenClose bug; remove when corrected AddFrame(toolbar); AddFrame(statusbar); Add(viewer.SizePos()); viewer.Margins(4); // viewer.SetZoom(Zoom(180, 1024)); viewer.WhenLink = THISBACK(OnLink); // viewer.SetReadOnly(); // Add(qtf.SizePos()); // qtf.WhenLink = THISBACK(OnLink); // qtf.BackPaint(); // qtf.WantFocus(); // qtf.SetFrame(InsetFrame()); // qtf.Background(White).Margins(10); // qtf.Zoom(160); } CONFIG_ITEM(DlgHelpTopic::config, "DlgHelpTopic", 1, 1, 1) void DlgHelpTopic::Serialize(Stream& stream) { SerializePlacement(stream); } void DlgHelpTopic::Run(String topic) { ReadConfigSelf(); OnZoom(); // update zoom if(OpenPage(topic)) { Open(); AddRecent(topic, viewer.GetSb()); TopWindow::Run(); WriteConfigSelf(); } } void DlgHelpTopic::Activate() { /* if(!IsNull(current_topic) && HelpTopicGetSeq() != help_topic_seq) { help_topic_seq = HelpTopicGetSeq(); const HelpTopicInfo& info = HelpTopicGet(current_topic); String title = info.GetTitle(); String text = info.GetText(); String style = HelpTopicGet(HelpDPPStyle()).GetText(); if(title != title_qtf || text != topic_qtf / * || style != style_qtf* /) SyncPage(title, text / *, style* /); } */ } bool DlgHelpTopic::OpenPage(String topic, int y) { Topic topicdata = GetTopic(topic); if(IsNull(topicdata.text)) { String langcode = LNGAsText(GetCurrentLanguage() & ~(-1 << 20)); String ltopic = topic; ltopic << '$' << ToLower(langcode); topicdata = GetTopic(ltopic); } /* const ArrayMap& map = HelpTopicMap(); int t = map.Find(topic); if(t < 0) { String appdoc = HelpAppDPP(topic); t = map.Find(appdoc); if(t < 0) { Exclamation(NFormat("Téma nápovědy [* \1%s\1] nebylo v systému nalezeno.", topic)); return false; } topic = appdoc; } //HelpIndex::Get().AddVisited(page.GetID()); // mark page as visited //int lang = GetCurrentLanguage(); const HelpTopicInfo& info = map[t]; String title = info.GetTitle(); String text = info.GetText(); */ String title = topicdata.title; String text = topicdata.text; if(IsNull(text)) { Exclamation(NFormat(t_("Help topic [* \1%s\1] not found."), topic)); return false; } // String style = HelpTopicGet(HelpDPPStyle()).GetText(); current_topic = topic; HelpTopic(current_topic); SyncPage(FromUtf8(title), text /*, style*/); ActiveFocus(viewer); viewer.SetSb(y); return true; } void DlgHelpTopic::SyncPage(WString title, String text /*, String style*/) { title = title; topic_qtf = text; // style_qtf = style; WString dlgt = title; if(IsNull(dlgt)) dlgt = t_("Help viewer"); else dlgt << t_(" - help viewer"); Title(dlgt); /* RichText out; RichPara title_para; title_para.format.after = 150; title_para.format.tab.Add().pos = 10000; RichPara::CharFormat format; // format.paper = Color(224, 224, 224); format.Face(Font::ARIAL).Height(150).Bold(); MQTFCat(title_para, title_qtf, format); out.Cat(title_para); AppendQTF(out, style_qtf + "\r\n" + topic_qtf); */ // int progress_pos; // Progress progress("Připravuji téma (%d)"); RichText txt = ParseQTF(topic_qtf); RichText out; out.SetStyles(txt.GetStyles()); RichPara title_para; title_para.format = out.GetStyle(out.GetStyleId("Heading")).format; title_para.Cat(title, title_para.format); out.Cat(title_para); out.CatPick(txt); // RichText out = HelpTopicExpand(/* style_qtf */ Null, title_qtf, topic_qtf, "Heading", false, 0, NoFormat(), Null, progress, progress_pos); // VectorMap eval; // eval.Add("$book", 1); // out.EvaluateFields(eval); int sb = viewer.GetSb(); viewer.Pick(out); viewer.SetSb(sb); // help_style = 0; } void DlgHelpTopic::AddRecent(String topic, int y) { recent_pages.SetCount(recent_pos); recent_y.SetCount(recent_pos); if(recent_pos == 0 || topic != recent_pages[recent_pos - 1] || y != recent_y[recent_pos - 1]) { recent_pages.Add(topic); recent_y.Add(y); } if((recent_pos = recent_pages.GetCount()) >= MAX_RECENT) { int over = recent_pos - MAX_RECENT; recent_pages.Remove(0, over); recent_y.Remove(0, over); recent_pos -= over; } Rescan(); } void DlgHelpTopic::OnLink(const String& link) { String new_topic = link; String old_topic = current_topic; int old_sb = viewer.GetSb(); if(OpenPage(new_topic)) { AddRecent(old_topic, old_sb); // SeekAnchor(s); AddRecent(new_topic, viewer.GetSb()); } } /* void DlgHelpTopic::SeekAnchor(const char *a) { if(!a) return; while(*a && *a != '#') a++; if(*a != '#') return; const Vector& vrc = qtf.GetValueRects(); int y = 0; for(int i = 0; i < vrc.GetCount(); i++) { String s = vrc[i].value; const char *p = s; if(*p != '=' || *++p != '#') continue; if(!strcmp(p, a)) { int t = vrc[i].rect.top; if(y == 0 || t < y) y = t; } } qtf.SetSb(y + qtf.GetTm()); } */ void DlgHelpTopic::OnBack() { if(recent_pos >= 2) { int t = --recent_pos - 1; OpenPage(recent_pages[t], recent_y[t]); } } void DlgHelpTopic::OnForward() { if(recent_pos < recent_pages.GetCount()) { int t = recent_pos++; OpenPage(recent_pages[t], recent_y[t]); } } void DlgHelpTopic::OnIndex() { String page = RunDlgHelpTopicIndex(); if(!IsNull(page)) OpenPage(page); /* String page = HelpIndex::Get().Run(HelpIndex::INDEX_TAB); const HelpPage *pp = HelpIndex::Get().Find(page); if(pp) { AddRecent(*current_page, dialog.qtf.GetSb()); OpenPage(*pp); SeekAnchor(page); AddRecent(*pp, dialog.qtf.GetSb()); } */ } void DlgHelpTopic::OnPrint() { DocReport report; Size page = report.GetPageSize(); ReportPageDraw rpd(page); PaintInfo info; info.sell = info.selh = 0; info.zoom = Zoom(1024, 1024); int doty = page.cy / info.zoom; // info.bottom = PageY(0, page.cy); viewer.Get().Paint(rpd, Rect(page), info); rpd.Write(report); report.Perform(); /* RichText rtext; AppendQtf(rtext, "[=A4* " + title_qtf); RichText::Format format; (RichText::CharFormat&)format = Arial(100); rtext.AppendPara(format); rtext.AppendPara(format); AppendQtf(rtext, topic_qtf); Report report; report.Qtf(AsQtf(rtext)); report.Perform(); */ } /* void DlgHelpTopic::ToolBookMenu(Bar& bar) { bar.Add("Příručka", DlgHelpViewImg::book(), THISBACK(OnBook)) .Key(K_SHIFT_CTRL_P) .Help("Vysázet uživatelskou příručku přímo pro tisk"); #ifdef _DEBUG #ifdef PLATFORM_WIN32 bar.Add("Uložit PDF", DlgHelpViewImg::book_pdf(), THISBACK(OnBookPDF)) .Help("Uložit uživatelskou příručku ve formátu PDF pro Adobe Acrobat Reader"); #endif bar.Add("Uložit RTF", DlgHelpViewImg::book_rtf(), THISBACK(OnBookRTF)) .Help("Uložit příručku ve formátu RTF (přenositelný formátovaný text)"); #endif } */ /* void DlgHelpTopic::OnBookRTF() { FileSel fsel; fsel.Type("RTF soubory (*.rtf)", "*.rtf") .AllFilesType() .DefaultExt("rtf"); static String recent; fsel <<= Nvl(recent, ConfigFile(GetExeTitle() + ".rtf")); if(fsel.ExecuteSaveAs("Uložit příručku (RTF)")) { recent = ~fsel; String manual = CreateHelpRTF(); if(!IsNull(manual)) { if(!SaveFile(recent, manual)) Exclamation(NFormat("Nelze uložit soubor [* \1%s\1] ([* %d] B).", recent, manual.GetLength())); } } } */ /* #ifdef PLATFORM_WIN32 void DlgHelpTopic::OnBookPDF() { FileSel fsel; fsel.Type("PDF soubory (*.pdf)", "*.pdf") .AllFilesType() .DefaultExt("pdf"); static String recent; fsel <<= Nvl(recent, ConfigFile(GetExeTitle() + ".pdf")); if(fsel.ExecuteSaveAs("Uložit příručku (PDF)")) { recent = ~fsel; String manual = CreateHelpPDF(); if(!IsNull(manual)) { if(!SaveFile(recent, manual)) Exclamation(NFormat("Nelze uložit soubor [* \1%s\1] ([* %d] B).", recent, manual.GetLength())); } } } #endif */ void DlgHelpTopic::OnZoom() { // dialog.qtf.Zoom(~zoom); // dialog.qtf.RefreshLayout(); // todo: Fidler's bug, remove as soon as possible } void DlgHelpTopic::ToolMain(Bar& bar) { bar.Add(recent_pos >= 2, t_("Previous"), DlgHelpViewImg::back(), THISBACK(OnBack)) .Key(K_ALT_LEFT) .Help(t_("Return to previous help topic")); bar.Add(recent_pos < recent_pages.GetCount(), t_("Next"), DlgHelpViewImg::forward(), THISBACK(OnForward)) .Key(K_ALT_RIGHT) .Help(t_("Move forward in order of viewing help topics")); bar.Separator(); bar.Add(t_("Search index"), DlgHelpViewImg::index(), THISBACK(OnIndex)) .Key(K_CTRL_F) .Help(t_("Show / select theme from the alphabetic index")); bar.Separator(); bar.Add(t_("Print"), DlgHelpViewImg::print(), THISBACK(OnPrint)) .Key(K_CTRL_P) .Help(t_("Print current topic on the printer")); HelpTopicBookMenu()(bar); } class DlgHelpLang : public WithHelpLangLayout { public: typedef DlgHelpLang CLASSNAME; DlgHelpLang(); bool Run(VectorMap& ext_lang, int& init_lang); private: void OnExtLangEdit(); void OnLangFileBrowse(); private: DropList lang_edit; EditField lang_file; ExtendedButton lang_file_browse; }; bool RunDlgHelpLang(VectorMap& ext_lang, int& init_lang) { return DlgHelpLang().Run(ext_lang, init_lang); } //RegisterHelpTopicObjectTitle(DlgHelpLang, t_("Application languages")) DlgHelpLang::DlgHelpLang() { CtrlLayoutOKCancel(*this, t_("Application languages")); HelpTopic("DlgHelpLang"); ext_lang.AutoHideSb(); ext_lang.AddColumn(t_("Language code"), 10).SetConvert(lang_edit).Edit(lang_edit); ext_lang.AddColumn(t_("Language file"), 30).Edit(lang_file); ext_lang.Inserting().Removing().NoAskRemove(); ext_lang.WhenArrayAction = THISBACK(OnExtLangEdit); lang_file.AddFrame(lang_file_browse); lang_file_browse <<= THISBACK(OnLangFileBrowse); for(const int *p = GetAllLanguages(); *p; p++) lang_edit.Add(*p, LNGAsText(*p)); } bool DlgHelpLang::Run(VectorMap& el, int& il) { int i; for(i = 0; i < el.GetCount(); i++) ext_lang.Add(el.GetKey(i), el[i]); OnExtLangEdit(); init_lang <<= il; if(TopWindow::Run() != IDOK) return false; el.Clear(); for(i = 0; i < ext_lang.GetCount(); i++) el.Add(ext_lang.Get(i, 0), ext_lang.Get(i, 1)); il = ~init_lang; return true; } void DlgHelpLang::OnExtLangEdit() { int oi = ~init_lang; init_lang.Clear(); const int *x = GetAllLanguages(); Index app_lang; while(*x) app_lang.Add(*x++); for(int i = 0; i < ext_lang.GetCount(); i++) app_lang.FindAdd(ext_lang.Get(i, 0)); Index lmask; for(int i = 0; i < app_lang.GetCount(); i++) { int l = app_lang[i], l0 = SetLNGCharset(l, CHARSET_DEFAULT); if(lmask.Find(l0) < 0) { lmask.Add(l0); init_lang.Add(l, LNGAsText(l0)); } } init_lang <<= (init_lang.FindKey(oi) < 0 ? app_lang[0] : oi); } void DlgHelpLang::OnLangFileBrowse() { FileSelector fsel; fsel.Type(t_("Language files (*.lng)"), t_("*.lng")); fsel.DefaultExt("lng"); fsel.AllFilesType(); fsel <<= String(~lang_file_browse); if(fsel.ExecuteOpen(t_("Language file"))) { lang_file_browse <<= ~fsel; lang_file_browse.Action(); } } END_UPP_NAMESPACE