1#include <Debug.h> 2#include "PDFWriter.h" 3#include "Bookmark.h" 4#include "Scanner.h" 5#include "Report.h" 6 7 8Bookmark::Definition::Definition(int level, BFont* font, bool expanded) 9 : fLevel(level) 10 , fFont(*font) 11 , fExpanded(expanded) 12{ 13} 14 15 16bool Bookmark::Definition::Matches(font_family* family, font_style* style, float size) const 17{ 18 font_family family0; 19 font_style style0; 20 21 if (fFont.Size() != size) return false; 22 23 fFont.GetFamilyAndStyle(&family0, &style0); 24 25 return strcmp(family0, *family) == 0 && 26 strcmp(style0, *style) == 0; 27} 28 29 30Bookmark::Bookmark(PDFWriter* writer) 31 : fWriter(writer) 32{ 33 for (int i = 0; i < kMaxBookmarkLevels; i ++) { 34 fLevels[i] = 0; 35 } 36} 37 38 39Bookmark::Definition* Bookmark::Find(BFont* font) const 40{ 41 font_family family; 42 font_style style; 43 float size; 44 45 font->GetFamilyAndStyle(&family, &style); 46 size = font->Size(); 47 48 for (int i = 0; i < fDefinitions.CountItems(); i++) { 49 Definition* definition = fDefinitions.ItemAt(i); 50 if (definition->Matches(&family, &style, size)) { 51 return definition; 52 } 53 } 54 return NULL; 55} 56 57 58void Bookmark::AddDefinition(int level, BFont* font, bool expanded) 59{ 60 ASSERT(1 <= level && level <= kMaxBookmarkLevels); 61 if (Find(font) == NULL) { 62 fDefinitions.AddItem(new Definition(level, font, expanded)); 63 } 64} 65 66 67void Bookmark::AddBookmark(BPoint start, float height, const char* text, BFont* font) 68{ 69 Definition* definition = Find(font); 70 if (definition != NULL) { 71 fOutlines.AddItem(new Outline(start, height, text, definition)); 72 } 73} 74 75 76int Bookmark::AscendingByStart(const Outline** a, const Outline** b) { 77 return (int)((*b)->Start().y - (*a)->Start().y); 78} 79 80 81void Bookmark::CreateBookmarks() { 82 char optList[256]; 83 fOutlines.SortItems(AscendingByStart); 84 85 for (int i = 0; i < fOutlines.CountItems(); i++) { 86 BString ucs2; 87 88 Outline* o = fOutlines.ItemAt(i); 89 REPORT(kInfo, fWriter->fPage, "Bookmark '%s' at level %d", o->Text(), o->Level()); 90 91 sprintf(optList, "type=fixed left=%f top=%f", o->Start().x, o->Start().y + o->Height()); 92 PDF_set_parameter(fWriter->fPdf, "bookmarkdest", optList); 93 94 fWriter->ToPDFUnicode(o->Text(), ucs2); 95 96 int open = o->Expanded() ? 1 : 0; 97 int bookmark = PDF_add_bookmark(fWriter->fPdf, ucs2.String(), fLevels[o->Level()-1], open); 98 99 if (bookmark < 0) bookmark = 0; 100 101 for (int i = o->Level(); i < kMaxBookmarkLevels; i ++) { 102 fLevels[i] = bookmark; 103 } 104 } 105 // reset to default 106 PDF_set_parameter(fWriter->fPdf, "bookmarkdest", "type=fitwindow"); 107 108 fOutlines.MakeEmpty(); 109} 110 111// Reads bookmark definitions from file 112 113/* 114File Format: Definition. 115Line comment starts with '#'. 116 117Definition = Version { Font }. 118Version = "Bookmarks" "2.0". 119Font = Level Family Style Size Expanded. 120Level = int. 121Family = String. 122Style = String. 123Size = float. 124Expanded = "expanded" | "collapsed". // new in version 2.0, version 1.0 defaults to collapsed 125String = '"' string '"'. 126*/ 127 128bool Bookmark::Exists(const char* f, const char* s) const { 129 font_family family; 130 font_style style; 131 uint32 flags; 132 int32 nFamilies; 133 int32 nStyles; 134 135 nFamilies = count_font_families(); 136 137 for (int32 i = 0; i < nFamilies; i ++) { 138 if (get_font_family(i, &family, &flags) == B_OK && strcmp(f, family) == 0) { 139 nStyles = count_font_styles(family); 140 for (int32 j = 0; j < nStyles; j++) { 141 if (get_font_style(family, j, &style, &flags) == B_OK && strcmp(s, style) == 0) { 142 return true; 143 } 144 } 145 } 146 } 147 return false; 148} 149 150 151bool Bookmark::Read(const char* name) { 152 Scanner scnr(name); 153 if (scnr.InitCheck() == B_OK) { 154 BString s; float version; bool ok; 155 ok = scnr.ReadName(&s) && scnr.ReadFloat(&version); 156 if (!ok || strcmp(s.String(), "Bookmarks") != 0 || (version != 1.0 && version != 2.0) ) { 157 REPORT(kError, 0, "Bookmarks (line %d, column %d): '%s' not a bookmarks file or wrong version!", scnr.Line(), scnr.Column(), name); 158 return false; 159 } 160 161 while (!scnr.IsEOF()) { 162 float level, size; 163 bool expanded = false; 164 BString family, style, expand; 165 if (!(scnr.ReadFloat(&level) && level >= 1.0 && level <= 10.0)) { 166 REPORT(kError, 0, "Bookmarks (line %d, column %d): Invalid level", scnr.Line(), scnr.Column()); 167 return false; 168 } 169 if (!scnr.ReadString(&family)) { 170 REPORT(kError, 0, "Bookmarks (line %d, column %d): Invalid font family", scnr.Line(), scnr.Column()); 171 return false; 172 } 173 if (!scnr.ReadString(&style)) { 174 REPORT(kError, 0, "Bookmarks (line %d, column %d): Invalid font style", scnr.Line(), scnr.Column()); 175 return false; 176 } 177 if (!scnr.ReadFloat(&size)) { 178 REPORT(kError, 0, "Bookmarks (line %d, column %d): Invalid font size", scnr.Line(), scnr.Column()); 179 return false; 180 } 181 if (version == 2.0) { 182 if (!scnr.ReadName(&expand) || (strcmp(expand.String(), "expanded") != 0 && strcmp(expand.String(), "collapsed") != 0)) { 183 REPORT(kError, 0, "Bookmarks (line %d, column %d): Invalid expanded value", scnr.Line(), scnr.Column()); 184 return false; 185 } 186 expanded = strcmp(expand.String(), "expanded") == 0; 187 } 188 189 if (Exists(family.String(), style.String())) { 190 BFont font; 191 font.SetFamilyAndStyle(family.String(), style.String()); 192 font.SetSize(size); 193 194 AddDefinition((int)level, &font, expanded); 195 } else { 196 REPORT(kWarning, 0, "Bookmarks (line %d, column %d): Font %s-%s not available!", scnr.Line(), scnr.Column(), family.String(), style.String()); 197 } 198 199 scnr.SkipSpaces(); 200 } 201 return true; 202 } else { 203 REPORT(kError, 0, "Bookmarks: Could not open bookmarks file '%d'", name); 204 } 205 return false; 206} 207