1 #include <wx/wx.h>
2 #include <wx/mstream.h>
3 #include <wx/stdpaths.h>
4 
5 
6 #include <crengine.h>
7 #include "cr3.h"
8 #include "wolopt.h"
9 #include "toc.h"
10 #include "optdlg.h"
11 #include "rescont.h"
12 #include "cr3.xpm"
13 #include <cr3version.h>
14 
15 //scan directory
16 //scan file
17 
wx2cr(wxString str)18 lString32 wx2cr( wxString str )
19 {
20     return lString32(str.utf8_str().data());
21 }
22 
cr2wx(lString32 str)23 wxString cr2wx( lString32 str )
24 {
25     lString8 s8 = UnicodeToUtf8(str);
26     return wxString(s8.c_str(), wxConvUTF8);
27 }
28 
29 /// author properties
30 class CRDocAuthor {
31     lString32 _firstName;
32     lString32 _lastName;
33     lString32 _middleName;
34     lString32 _nickName;
35 public:
CRDocAuthor()36     CRDocAuthor() { }
~CRDocAuthor()37     ~CRDocAuthor() { }
CRDocAuthor(const CRDocAuthor & v)38     CRDocAuthor( const CRDocAuthor & v ) {
39         _firstName = v._firstName;
40         _lastName = v._lastName;
41         _middleName = v._middleName;
42         _nickName = v._nickName;
43     }
operator =(const CRDocAuthor & v)44     CRDocAuthor & operator = ( const CRDocAuthor & v ) {
45         _firstName = v._firstName;
46         _lastName = v._lastName;
47         _middleName = v._middleName;
48         _nickName = v._nickName;
49         return *this;
50     }
getFirstName()51     lString32 getFirstName() { return _firstName; }
getLastName()52     lString32 getLastName() { return _lastName; }
getMiddleName()53     lString32 getMiddleName() { return _middleName; }
getNickName()54     lString32 getNickName() { return _nickName; }
setFirstName(lString32 fn)55     void setFirstName( lString32 fn ) { _firstName = fn; }
setLastName(lString32 ln)56     void setLastName( lString32 ln ) { _lastName = ln; }
getMiddleName(lString32 mn)57     void getMiddleName( lString32 mn ) { _middleName = mn; }
getNickName(lString32 nn)58     void getNickName( lString32 nn ) { _nickName = nn; }
59 };
60 
61 /// document properties container
62 class CRDocProperties {
63     lString32 _fileName;
64     lvsize_t  _fileSize;
65     doc_format_t _format;
66     lString32  _title;
67     lString32  _seriesName;
68     int        _seriesNumber;
69     LVPtrVector<CRDocAuthor> _authors;
70 public:
71     /// returns array of document authors
getAuthors()72     LVPtrVector<CRDocAuthor> & getAuthors() { return _authors; }
73     /// returns document file name
getFileName()74     lString32 getFileName() { return _fileName; }
75     /// returns document file size
getFileSize()76     lvsize_t getFileSize() { return _fileSize; }
77     /// returns document format
getFormat()78     doc_format_t getFormat() { return _format; }
79     /// returns document title
getTitle()80     lString32 getTitle() { return _title; }
81     /// returns document series name
getSeriesName()82     lString32 getSeriesName() { return _seriesName; }
83     /// returns document series number
getSeriesNumber()84     int getSeriesNumber() { return _seriesNumber; }
setFileName(lString32 fn)85     void setFileName( lString32 fn ) { _fileName = fn; }
setFileSize(lvsize_t sz)86     void setFileSize( lvsize_t sz ) { _fileSize = sz; }
setFormat(doc_format_t fmt)87     void setFormat( doc_format_t fmt ) { _format = fmt; }
setTitle(lString32 title)88     void setTitle( lString32 title ) { _title = title; }
setSeriesName(lString32 sn)89     void setSeriesName( lString32 sn ) {  _seriesName = sn; }
setSeriesNumber(int sn)90     void setSeriesNumber( int sn ) { _seriesNumber = sn; }
CRDocProperties()91     CRDocProperties() : _seriesNumber(0)
92     {
93     }
~CRDocProperties()94     ~CRDocProperties()
95     {
96     }
97 };
98 
99 /// file properties container
100 class CRFileProperties {
101     lString32 _storageBasePath;
102     lString32 _relativePath;
103     lString32 _fileName;
104     lvsize_t  _fileSize;
105     bool      _isArchieve;
106     LVPtrVector<CRDocProperties> _docList;
107     lString32  _mimeType;
108     //===============================================
readDocument(lString32 fileName,LVStreamRef stream)109     bool readDocument( lString32 fileName, LVStreamRef stream )
110     {
111         return true;
112     }
readEpub(LVContainerRef arc)113     bool readEpub( LVContainerRef arc )
114     {
115         lString32 rootfilePath;
116         lString32 rootfileMediaType;
117         // read container.xml
118         {
119             LVStreamRef container_stream = arc->OpenStream(U"META-INF/container.xml", LVOM_READ);
120             if ( !container_stream.isNull() ) {
121                 ldomDocument * doc = LVParseXMLStream( container_stream );
122                 if ( doc ) {
123                     ldomNode * rootfile = doc->nodeFromXPath( lString32("container/rootfiles/rootfile") );
124                     if ( rootfile && rootfile->isElement() ) {
125                         rootfilePath = rootfile->getAttributeValue("full-path");
126                         rootfileMediaType = rootfile->getAttributeValue("media-type");
127                     }
128                     delete doc;
129                 }
130             }
131         }
132         lString32 codeBase;
133         if (!rootfilePath.empty() && rootfileMediaType == "application/oebps-package+xml") {
134             //
135             {
136                 int lastSlash = -1;
137                 for ( int i=0; i<(int)rootfilePath.length(); i++ )
138                     if ( rootfilePath[i]=='/' )
139                         lastSlash = i;
140                 if ( lastSlash>0 )
141                     codeBase = lString32( rootfilePath.c_str(), lastSlash + 1);
142             }
143             LVStreamRef content_stream = arc->OpenStream(rootfilePath.c_str(), LVOM_READ);
144             if ( !content_stream.isNull() ) {
145                 ldomDocument * doc = LVParseXMLStream( content_stream );
146                 if ( doc ) {
147                     lString32 title = doc->textFromXPath( lString32("package/metadata/title") );
148                     lString32 authors = doc->textFromXPath( lString32("package/metadata/creator") );
149                     delete doc;
150                 }
151             }
152         }
153         return false;
154     }
readArchieve(LVContainerRef arc)155     bool readArchieve( LVContainerRef arc )
156     {
157         // epub support
158         LVStreamRef mtStream = arc->OpenStream(U"mimetype", LVOM_READ );
159         if ( !mtStream.isNull() ) {
160             int size = mtStream->GetSize();
161             if ( size>4 && size<100 ) {
162                 LVArray<char> buf( size+1, 0 );
163                 if ( mtStream->Read( buf.get(), size, NULL )==LVERR_OK ) {
164                     for ( int i=0; i<size; i++ )
165                         if ( buf[i]<32 || ((unsigned char)buf[i])>127 )
166                             buf[i] = 0;
167                     buf[size] = 0;
168                     if ( buf[0] )
169                         _mimeType = Utf8ToUnicode( lString8( buf.get() ) );
170                 }
171             }
172         }
173         if (_mimeType == "application/epub+zip")
174             return readEpub( arc );
175         // todo: add more mime types support here
176         for ( int i=0; i<arc->GetObjectCount(); i++ ) {
177             const LVContainerItemInfo * item = arc->GetObjectInfo( i );
178             if ( !item->IsContainer() ) {
179                 LVStreamRef stream = arc->OpenStream( item->GetName(), LVOM_READ );
180                 if ( !stream.isNull() ) {
181                     readDocument( lString32(item->GetName() ), stream );
182                 }
183             }
184         }
185         return _docList.length() > 0;
186     }
187 public:
readFileProps(lString32 storageBasePath,lString32 filePathName)188     bool readFileProps( lString32 storageBasePath, lString32 filePathName )
189     {
190         LVAppendPathDelimiter( storageBasePath );
191         if ( filePathName.startsWith( storageBasePath ) ) {
192             _storageBasePath = storageBasePath;
193             _relativePath = filePathName.substr( _storageBasePath.length() );
194             _fileName = LVExtractFilename( _relativePath );
195             _relativePath = LVExtractPath( _relativePath );
196         } else {
197             _storageBasePath.clear();
198             _fileName = LVExtractFilename( filePathName );
199             _relativePath = LVExtractPath( filePathName );
200         }
201         _mimeType.clear();
202         LVStreamRef stream = LVOpenFileStream( filePathName.c_str(), LVOM_READ );
203         if ( stream.isNull() )
204             return false;
205         _fileSize = stream->GetSize();
206         LVContainerRef arc = LVOpenArchieve( stream );
207         _isArchieve = !arc.isNull();
208         if ( _isArchieve )
209             return readArchieve( arc );
210         else
211             return readDocument( _fileName, stream );
212     }
CRFileProperties()213     CRFileProperties() : _fileSize(0), _isArchieve(false)
214     {
215     }
~CRFileProperties()216     virtual ~CRFileProperties()
217     {
218     }
219 };
220 
221 
222 /*
223  For LINUX:
224 
225    /usr/share/crengine/fonts/*.ttf    -- fonts
226    /usr/share/fonts/truetype/freefont/*.ttf -- alternative font directory
227    /usr/share/fonts/truetype/msttcorefonts/ -- MS arial, times and courier fonts
228    /usr/share/crengine/fb2.css        -- stylesheet
229    /usr/share/crengine/hyph/Russian_EnUS_hyphen_(Alan).pdb   -- hyphenation dictionary
230 
231 */
232 
233 
BEGIN_EVENT_TABLE(cr3Frame,wxFrame)234 BEGIN_EVENT_TABLE( cr3Frame, wxFrame )
235     EVT_MENU( Menu_File_Quit, cr3Frame::OnQuit )
236     EVT_MENU( Menu_File_About, cr3Frame::OnAbout )
237     EVT_MENU( wxID_OPEN, cr3Frame::OnFileOpen )
238     EVT_MENU( wxID_SAVE, cr3Frame::OnFileSave )
239     EVT_MENU( Menu_View_TOC, cr3Frame::OnShowTOC )
240     EVT_MENU( Menu_File_Options, cr3Frame::OnShowOptions )
241     EVT_MENU( Menu_View_History, cr3Frame::OnShowHistory )
242     EVT_MENU( Menu_View_Rotate, cr3Frame::OnRotate )
243 
244 
245     EVT_MENU_RANGE( 0, 0xFFFF, cr3Frame::OnCommand )
246 //    EVT_UPDATE_UI_RANGE( 0, 0xFFFF, cr3Frame::OnUpdateUI )
247     EVT_COMMAND_SCROLL( Window_Id_Scrollbar, cr3Frame::OnScroll )
248     EVT_CLOSE( cr3Frame::OnClose )
249     EVT_MOUSEWHEEL( cr3Frame::OnMouseWheel )
250     EVT_INIT_DIALOG( cr3Frame::OnInitDialog )
251     EVT_LIST_ITEM_ACTIVATED(Window_Id_HistList, cr3Frame::OnHistItemActivated)
252     //EVT_SIZE    ( cr3Frame::OnSize )
253 END_EVENT_TABLE()
254 
255 
256 BEGIN_EVENT_TABLE( cr3scroll, wxScrollBar )
257     EVT_SET_FOCUS( cr3scroll::OnSetFocus )
258 END_EVENT_TABLE()
259 
260 IMPLEMENT_APP(cr3app)
261 
262 
263 #define USE_XPM_BITMAPS 1
264 
265 
266 #include "resources/cr3res.h"
267 
268 
269 void testHyphen( const char * str )
270 {
271     lString32 s32 = Utf8ToUnicode( lString8(str) );
272     lUInt16 widths[16] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15};
273     lUInt8 flags[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
274     HyphMan::hyphenate( s32.c_str(), s32.length(), widths, flags, 1, 15 );
275     lString8 buf( str );
276     buf << " = ";
277     for ( int i=0; i<s32.length(); i++ ) {
278         buf << str[i];
279         if ( flags[i] & LCHAR_ALLOW_HYPH_WRAP_AFTER )
280             buf << '-';
281     }
282     printf("%s\n", buf.c_str());
283 }
284 
testFormatting()285 void testFormatting()
286 {
287     //
288     static char * words[] = {
289         "audition",
290         "helper",
291         "automation",
292         "constant",
293         "culture",
294         "hyphenation",
295         NULL,
296     };
297     for ( int w=0; words[w]; w++ )
298         testHyphen(words[w]);
299     class Tester {
300         public:
301             LFormattedText txt;
302             void addLine( const lChar32 * str, int flags, LVFontRef font )
303             {
304                 lString32 s( str );
305                 txt.AddSourceLine(
306                         s.c_str(),        /* pointer to unicode text string */
307                 s.length(),         /* number of chars in text, 0 for auto(strlen) */
308                 0x000000,       /* text color */
309                 0xFFFFFF,     /* background color */
310                 font.get(),        /* font to draw string */
311                 NULL,
312                 flags,
313                 16,    /* interline space, *16 (16=single, 32=double) */
314                 30,    /* first line margin */
315                 NULL,
316                 0
317                                  );
318             }
319             void dump()
320             {
321                 formatted_text_fragment_t * buf = txt.GetBuffer();
322                 for ( unsigned i=0; i<buf->frmlinecount; i++ ) {
323                     formatted_line_t   * frmline = buf->frmlines[i];
324                     printf("line[%d]\t ", i);
325                     for ( unsigned j=0; j<frmline->word_count; j++ ) {
326                         formatted_word_t * word = &frmline->words[j];
327                         if ( word->flags & LTEXT_WORD_IS_OBJECT ) {
328                             // object
329                             printf("{%d..%d} object\t", (int)word->x, (int)(word->x + word->width) );
330                         } else {
331                             // dump text
332                             src_text_fragment_t * src = &buf->srctext[word->src_text_index];
333                             lString32 txt = lString32( src->t.text, word->t.start, word->t.len );
334                             lString8 txt8 = UnicodeToUtf8( txt );
335                             printf("{%d..%d} \"%s\"\t", (int)word->x, (int)(word->x + word->width), (const char *)txt8.c_str() );
336                         }
337                     }
338                     printf("\n");
339                 }
340             }
341     };
342     LVFontRef font1 = fontMan->GetFont(20, 300, false, css_ff_sans_serif, lString8("Arial") );
343     LVFontRef font2 = fontMan->GetFont(20, 300, false, css_ff_serif, lString8("Times New Roman") );
344     Tester t;
345     t.addLine( U"   Testing preformatted\ntext wrapping.", LTEXT_ALIGN_WIDTH|LTEXT_FLAG_OWNTEXT, font1 );
346     t.addLine( U"\nNewline.", LTEXT_FLAG_OWNTEXT, font1 );
347     t.addLine( U"\n\n2 Newlines.", LTEXT_FLAG_OWNTEXT, font1 );
348 #if 0
349     t.addLine( U"Testing thisislonglongwordto", LTEXT_ALIGN_WIDTH|LTEXT_FLAG_OWNTEXT, font1 );
350     t.addLine( U"Testing", LTEXT_ALIGN_WIDTH|LTEXT_FLAG_OWNTEXT, font1 );
351     t.addLine( U"several", LTEXT_ALIGN_LEFT|LTEXT_FLAG_OWNTEXT, font2 );
352     t.addLine( U" short", LTEXT_FLAG_OWNTEXT, font1 );
353     t.addLine( U"words!", LTEXT_FLAG_OWNTEXT, font2 );
354     t.addLine( U"Testing thisislonglongwordtohyphenate simple paragraph formatting. Just a test. ", LTEXT_ALIGN_WIDTH|LTEXT_FLAG_OWNTEXT, font1 );
355     t.addLine( U"There is seldom reason to tag a file in isolation. A more common use is to tag all the files that constitute a module with the same tag at strategic points in the development life-cycle, such as when a release is made.", LTEXT_ALIGN_WIDTH|LTEXT_FLAG_OWNTEXT, font1 );
356     t.addLine( U"There is seldom reason to tag a file in isolation. A more common use is to tag all the files that constitute a module with the same tag at strategic points in the development life-cycle, such as when a release is made.", LTEXT_ALIGN_WIDTH|LTEXT_FLAG_OWNTEXT, font1 );
357     t.addLine( U"There is seldom reason to tag a file in isolation. A more common use is to tag all the files that constitute a module with the same tag at strategic points in the development life-cycle, such as when a release is made.", LTEXT_ALIGN_WIDTH|LTEXT_FLAG_OWNTEXT, font1 );
358     t.addLine( U"Next paragraph: left-aligned. Blabla bla blabla blablabla hdjska hsdjkasld hsdjka sdjaksdl hasjkdl ahklsd hajklsdh jaksd hajks dhjksdhjshd sjkdajsh hasjdkh ajskd hjkhjksajshd hsjkadh sjk.", LTEXT_ALIGN_LEFT|LTEXT_FLAG_OWNTEXT, font1 );
359     t.addLine( U"Testing thisislonglongwordtohyphenate simple paragraph formatting. Just a test. ", LTEXT_ALIGN_WIDTH|LTEXT_FLAG_OWNTEXT, font1 );
360     t.addLine( U"Another fragment of text. ", LTEXT_FLAG_OWNTEXT, font1 );
361     t.addLine( U"And the last one written with another font", LTEXT_FLAG_OWNTEXT, font2 );
362     t.addLine( U"Next paragraph: left-aligned. ", LTEXT_ALIGN_LEFT|LTEXT_FLAG_OWNTEXT, font1 );
363     t.addLine( U"One more sentence. Second sentence.", LTEXT_FLAG_OWNTEXT, font1 );
364     int i;
365 #endif
366 //    t.txt.FormatNew( 300, 400 );
367     t.dump();
368 #if 0
369     printf("Running performance test\n");
370     time_t start1 = time((time_t*)0);
371     for ( i=0; i<2000; i++ )
372         t.txt.FormatNew( 600, 800 );
373     //for ( int i=0; i<100000; i++ )
374     //    t.txt.FormatNew( 400, 300 );
375     time_t end1 = time((time_t*)0);
376 #endif
377 #if 0
378     time_t start2 = time((time_t*)0);
379     for ( i=0; i<2000; i++ )
380         t.txt.FormatOld( 600, 800 );
381     //for ( int i=0; i<100000; i++ )
382     //    t.txt.FormatOld( 400, 300 );
383     time_t end2 = time((time_t*)0);
384 #endif
385 #if 0
386     int time1 = (int)(end1-start1);
387     int time2 = (int)(end2-start2);
388     printf("\nNew time = %d, old time = %d, gain=%d%%\n", time1, time2, (time2-time1)*100/time2);
389 #endif
390     exit(0);
391 }
392 
393 
394 ResourceContainer * resources = NULL;
395 
detectSlash(lString32 path)396 static lChar32 detectSlash( lString32 path )
397 {
398     for ( int i=0; i<path.length(); i++ )
399         if ( path[i]=='\\' || path[i]=='/' )
400             return path[i];
401 #ifdef _WIN32
402     return '\\';
403 #else
404     return '/';
405 #endif
406 }
407 
GetConfigFileName()408 lString32 GetConfigFileName()
409 {
410     wxString wxcfgdir = wxStandardPaths::Get().GetUserDataDir();
411     if ( !wxDirExists( wxcfgdir ) )
412         ::wxMkdir( wxString( wxcfgdir ) );
413     lString32 cfgdir = wx2cr(wxcfgdir);
414     lChar32 slash = detectSlash( cfgdir );
415     cfgdir << slash;
416     return cfgdir + "cr3.ini";
417 }
418 
OnUpdateUI(wxUpdateUIEvent & event)419 void cr3Frame::OnUpdateUI( wxUpdateUIEvent& event )
420 {
421 }
422 
OnClose(wxCloseEvent & event)423 void cr3Frame::OnClose( wxCloseEvent& event )
424 {
425     SaveOptions();
426     _view->CloseDocument();
427     Destroy();
428 }
429 
430 
OnHistItemActivated(wxListEvent & event)431 void cr3Frame::OnHistItemActivated( wxListEvent& event )
432 {
433     long index = event.GetIndex();
434     if ( index == 0 && _view->getDocView()->isDocumentOpened()) {
435         SetActiveMode( am_book );
436         return;
437     }
438     if ( index>=0 && index<_view->getDocView()->getHistory()->getRecords().length() ) {
439         lString32 pathname = _view->getDocView()->getHistory()->getRecords()[index]->getFilePath() +
440             _view->getDocView()->getHistory()->getRecords()[index]->getFileName();
441         if ( !pathname.empty() ) {
442             Update();
443             SetActiveMode( am_book );
444             _view->LoadDocument( cr2wx(pathname) );
445             UpdateToolbar();
446         }
447     }
448 }
449 
OnCommand(wxCommandEvent & event)450 void cr3Frame::OnCommand( wxCommandEvent& event )
451 {
452     _view->OnCommand( event );
453     switch ( event.GetId() ) {
454     case Menu_View_ToggleFullScreen:
455         _isFullscreen = !_isFullscreen;
456 				_view->SetFullScreenState(_isFullscreen);
457         ShowFullScreen( _isFullscreen );
458         break;
459     case Menu_View_ZoomIn:
460     case Menu_View_ZoomOut:
461     case Menu_View_NextPage:
462     case Menu_View_PrevPage:
463     case Menu_Link_Forward:
464     case Menu_Link_Back:
465     case Menu_Link_Next:
466     case Menu_Link_Prev:
467     case Menu_Link_Go:
468     case Menu_View_Text_Format:
469         break;
470     }
471 }
472 
OnMouseWheel(wxMouseEvent & event)473 void cr3Frame::OnMouseWheel(wxMouseEvent& event)
474 {
475     _view->OnMouseWheel(event);
476 }
477 
OnSize(wxSizeEvent & event)478 void cr3Frame::OnSize(wxSizeEvent& event)
479 {
480     if ( _props->getBoolDef(PROP_WINDOW_SHOW_STATUSBAR, true ) ) {
481         wxStatusBar * sb = GetStatusBar();
482         if ( sb ) {
483             int width, height;
484             GetClientSize( &width, &height );
485             int sw[3] = {width-200, 100, 100};
486             sb->SetStatusWidths( 3, sw );
487         }
488     }
489 }
490 
491 
initHyph(const char * fname)492 bool initHyph(const char * fname)
493 {
494     //HyphMan hyphman;
495     //return;
496 
497     //LVStreamRef stream = LVOpenFileStream( fname, LVOM_READ);
498     //if (!stream)
499    // {
500     //    printf("Cannot load hyphenation file %s\n", fname);
501     //    return false;
502    // }
503     // stream.get()
504     return HyphMan::initDictionaries( lString32(fname) );
505 }
506 
readFileToString(const char * fname)507 lString8 readFileToString( const char * fname )
508 {
509     lString8 buf;
510     LVStreamRef stream = LVOpenFileStream(fname, LVOM_READ);
511     if (!stream)
512         return buf;
513     int sz = stream->GetSize();
514     if (sz>0)
515     {
516         buf.insert( 0, sz, ' ' );
517         stream->Read( buf.modify(), sz, NULL );
518     }
519     return buf;
520 }
521 
522 
OnExit()523 int cr3app::OnExit()
524 {
525     ShutdownFontManager();
526     delete resources;
527     HyphMan::uninit();
528 #if LDOM_USE_OWN_MEM_MAN == 1
529     //ldomFreeStorage();
530 #endif
531     return 0;
532 }
533 
getIcon16x16(const lChar32 * name)534 wxBitmap cr3Frame::getIcon16x16(const lChar32 *name )
535 {
536     wxLogNull logNo; // Temporary disable warnings ( see: http://trac.wxwidgets.org/ticket/15331 )
537     lString32 dir;
538     if ( _toolbarSize==2 )
539         dir = "icons/22x22/";
540     else if ( _toolbarSize==1 )
541         dir = "icons/16x16/";
542     else
543         dir = "icons/32x32/";
544     wxBitmap icon = resources->GetBitmap( (dir + name + ".png").c_str() );
545     if ( icon.IsOk() )
546         return icon;
547     return wxNullBitmap;
548 } // ~wxLogNull called, old log sink restored
549 
550 #if (USE_FREETYPE==1)
getDirectoryFonts(lString32Collection & pathList,lString32 ext,lString32Collection & fonts,bool absPath)551 bool getDirectoryFonts( lString32Collection & pathList, lString32 ext, lString32Collection & fonts, bool absPath )
552 {
553     int foundCount = 0;
554     lString32 path;
555     for ( int di=0; di<pathList.length();di++ ) {
556         path = pathList[di];
557         LVContainerRef dir = LVOpenDirectory(path.c_str());
558         if ( !dir.isNull() ) {
559             CRLog::trace("Checking directory %s", UnicodeToUtf8(path).c_str() );
560             for ( int i=0; i < dir->GetObjectCount(); i++ ) {
561                 const LVContainerItemInfo * item = dir->GetObjectInfo(i);
562                 lString32 fileName = item->GetName();
563                 lString8 fn = UnicodeToLocal(fileName);
564                     //printf(" test(%s) ", fn.c_str() );
565                 if ( !item->IsContainer() && fileName.length()>4 && lString32(fileName, fileName.length()-4, 4)==ext ) {
566                     lString32 fn;
567                     if ( absPath ) {
568                         fn = path;
569                         if ( !fn.empty() && fn[fn.length()-1]!=PATH_SEPARATOR_CHAR)
570                             fn << PATH_SEPARATOR_CHAR;
571                     }
572                     fn << fileName;
573                     foundCount++;
574                     fonts.add( fn );
575                 }
576             }
577         }
578     }
579     return foundCount > 0;
580 }
581 #endif
582 
583 bool
OnInit()584 cr3app::OnInit()
585 {
586 #if 0
587     // test property container unit test
588     {
589         CRPropRef props = LVCreatePropsContainer();
590         props->setString("test.string.values.1", lString32("string value 1"));
591         props->setString("test.string.values.2", lString32("string value 2 with extra chars(\\\r\n)"));
592         props->setBool("test.string.boolean1", true);
593         props->setBool("test.string.boolean2", false);
594         props->setString("test.string.more_values.2", lString32("string more values (2)"));
595         props->setString("test.string.values.22", lString32("string value 22"));
596         props->setInt("test.int.value1", 1 );
597         props->setInt("test.int.value2", -2 );
598         props->setInt("test.int.value3", 3 );
599         props->setInt("test.int.value4", 4 );
600         props->setInt64("test.int.big-value1", -42387267 );
601         props->setPoint("test.points.1", lvPoint(1,2) );
602         props->setPoint("test.points.2", lvPoint(3,4) );
603         props->setRect("test.rects.1", lvRect(1,2,3,4) );
604         props->setRect("test.rects.2", lvRect(-1,-2,3,4) );
605         props->setRect("test.rects.1copy", props->getRectDef("test.rects.1", lvRect()) );
606         props->setPoint("test.points.1copy", props->getPointDef("test.points.1", lvPoint()) );
607         props->setColor("test.colors.1", 0x012345);
608         props->setColor("test.colors.1copy", props->getColorDef("test.colors.1") );
609         CRPropRef sub = props->getSubProps("test.string.");
610         props->setString("test.results.values.1", sub->getStringDef("values.2"));
611         props->setInt("test.results.str-items", sub->getCount());
612         props->setString("test.results.item1-value", sub->getValue(1));
613         props->setString("test.results.item2-name", Utf8ToUnicode(lString8(sub->getName(2))));
614         props->setBool("test.results.compare-chars-eq", sub->getStringDef("values.2")==lString32("string value 2 with extra chars(\\\r\n)") );
615         LVStreamRef stream = LVOpenFileStream( "props1.ini", LVOM_WRITE );
616         props->saveToStream( stream.get() );
617     }
618     {
619         CRPropRef props = LVCreatePropsContainer();
620         LVStreamRef istream = LVOpenFileStream( "props1.ini", LVOM_READ );
621         LVStreamRef ostream = LVOpenFileStream( "props2.ini", LVOM_WRITE );
622         if ( !istream.isNull() && !ostream.isNull() ) {
623             props->loadFromStream( istream.get() );
624             props->setBool("add.test.result", props->getIntDef("test.int.value2", 0)==-2 );
625             props->saveToStream( ostream.get() );
626         }
627     }
628 #endif
629 
630 #if 0
631     //CRLog::setFileLogger( "crengine.log" );
632     CRLog::setStdoutLogger();
633     CRLog::setLogLevel( CRLog::LL_DEBUG );
634 #endif
635 
636     wxImage::AddHandler(new wxPNGHandler);
637     resources = new ResourceContainer();
638 
639     lString32 appname = wx2cr(argv[0]);
640     int lastSlash=-1;
641     lChar32 slashChar = '/';
642     for ( int p=0; p<(int)appname.length(); p++ ) {
643         if ( appname[p]=='\\' ) {
644             slashChar = '\\';
645             lastSlash = p;
646         } else if ( appname[p]=='/' ) {
647             slashChar = '/';
648             lastSlash=p;
649         }
650     }
651 
652     lString32 appPath;
653     if ( lastSlash>=0 )
654         appPath = appname.substr( 0, lastSlash+1 );
655 
656 #if 0
657     {
658         LVStreamRef stream = LVOpenFileStream( "cr3res.zip", LVOM_WRITE );
659         stream->Write( cr3_icons, sizeof(cr3_icons), NULL );
660     }
661 #endif
662 
663 
664     if (resources->OpenFromMemory( cr3_icons, sizeof(cr3_icons) )) {
665 /*
666         LVStreamRef testStream = resources.GetStream(U"icons/16x16/signature.png");
667         if ( !testStream.isNull() ) {
668             int sz = testStream->GetSize();
669             lUInt8 * buf = new lUInt8[ sz ];
670             testStream->Read(buf, sz, NULL);
671             printf("read: %c%c%c\n", buf[0], buf[1], buf[2]);
672         }
673         wxBitmap icon = resources.GetBitmap(U"icons/16x16/signature.png");
674         if ( icon.IsOk() ) {
675             printf( "Image opened: %dx%d:%d\n", icon.GetWidth(), icon.GetHeight(), icon.GetDepth() );
676         }
677 */
678     }
679     lString32 fontDir = appPath + "fonts";
680     fontDir << slashChar;
681     lString8 fontDir8 = UnicodeToLocal(fontDir);
682     const char * fontDir8s = fontDir8.c_str();
683     //InitFontManager( fontDir8 );
684     InitFontManager(lString8::empty_str);
685 
686     // Load font definitions into font manager
687     // fonts are in files font1.lbf, font2.lbf, ... font32.lbf
688     if (!fontMan->GetFontCount()) {
689 
690 
691 #if (USE_FREETYPE==1)
692     lString32 fontExt = U".ttf";
693 #else
694     lString32 fontExt = U".lbf";
695 #endif
696 #if (USE_FREETYPE==1)
697     lString32Collection fonts;
698     lString32Collection fontDirs;
699     fontDirs.add( fontDir );
700     static const char * msfonts[] = {
701         "arial.ttf", "arialbd.ttf", "ariali.ttf", "arialbi.ttf",
702         "cour.ttf", "courbd.ttf", "couri.ttf", "courbi.ttf",
703         "times.ttf", "timesbd.ttf", "timesi.ttf", "timesbi.ttf",
704         NULL
705     };
706 #ifdef _WIN32
707     wchar_t sd_buf[MAX_PATH];
708     sd_buf[0] = 0;
709     ::GetSystemDirectoryW(sd_buf, MAX_PATH-1);
710     lString32 sysFontDir = lString32(sd_buf) + U"\\..\\fonts\\";
711     lString8 sfd = UnicodeToLocal( sysFontDir );
712     //const char * s = sfd.c_str();
713     //CRLog::debug(s);
714     for ( int fi=0; msfonts[fi]; fi++ )
715         fonts.add( sysFontDir + lString32(msfonts[fi]) );
716 #endif
717 #ifdef _LINUX
718     fontDirs.add("/usr/local/share/cr3/fonts");
719     fontDirs.add("/usr/local/share/fonts/truetype/freefont");
720     fontDirs.add("/usr/share/cr3/fonts");
721     fontDirs.add("/usr/share/fonts/truetype/freefont");
722     //fontDirs.add( lString32(U"/usr/share/fonts/truetype/msttcorefonts") );
723     for ( int fi=0; msfonts[fi]; fi++ )
724         fonts.add( lString32("/usr/share/fonts/truetype/msttcorefonts/") + lString32(msfonts[fi]) );
725 #endif
726     getDirectoryFonts( fontDirs, fontExt, fonts, true );
727 
728     // load fonts from file
729     CRLog::debug("%d font files found", fonts.length());
730     if (!fontMan->GetFontCount()) {
731         for ( int fi=0; fi<fonts.length(); fi++ ) {
732             lString8 fn = UnicodeToLocal(fonts[fi]);
733             CRLog::trace("loading font: %s", fn.c_str());
734             if ( !fontMan->RegisterFont(fn) ) {
735                 CRLog::trace("    failed\n");
736             }
737         }
738     }
739 #if 0
740         LVContainerRef dir = LVOpenDirectory(fontDir.c_str());
741         for ( int i=0; i<dir->GetObjectCount(); i++ ) {
742             const LVContainerItemInfo * item = dir->GetObjectInfo(i);
743             lString32 fileName = item->GetName();
744             lString32 fileNameLower = fileName;
745             fileNameLower.lowercase();
746             lString8 fn = UnicodeToLocal(fileName);
747             const char * pfn = fn.c_str();
748             if ( !item->IsContainer() && fileNameLower.length()>4 && lString32(fileNameLower, fileNameLower.length()-4, 4)==U".ttf" ) {
749                 printf("loading font: %s\n", fn.c_str());
750                 if ( !fontMan->RegisterFont(fn) ) {
751                     printf("    failed\n");
752                 }
753             }
754         }
755 #endif
756         //fontMan->RegisterFont(lString8("arial.ttf"));
757 #else
758         #define MAX_FONT_FILE 128
759         for (int i=0; i<MAX_FONT_FILE; i++)
760         {
761             char fn[1024];
762             sprintf( fn, "font%d.lbf", i );
763             printf("try load font: %s\n", fn);
764             fontMan->RegisterFont( lString8(fn) );
765         }
766 #endif
767     }
768 
769     // init hyphenation manager
770     char hyphfn[1024];
771     sprintf(hyphfn, "Russian_EnUS_hyphen_(Alan).pdb" );
772     if ( !initHyph( (UnicodeToLocal(appPath) + hyphfn).c_str() ) ) {
773 #ifdef _LINUX
774         initHyph( "/usr/share/cr3/hyph/Russian_EnUS_hyphen_(Alan).pdb" );
775 #endif
776     }
777 
778     if (!fontMan->GetFontCount())
779     {
780         //error
781 #if (USE_FREETYPE==1)
782         printf("Fatal Error: Cannot open font file(s) .ttf \nCannot work without font\n" );
783 #else
784         printf("Fatal Error: Cannot open font file(s) font#.lbf \nCannot work without font\nUse FontConv utility to generate .lbf fonts from TTF\n" );
785 #endif
786         return FALSE;
787     }
788 
789     printf("%d fonts loaded.\n", fontMan->GetFontCount());
790 
791     int argc = wxGetApp().argc;
792     lString32 fnameToOpen;
793     for ( int i=1; i<argc; i++ ) {
794         lString32 param = wx2cr(wxGetApp().argv[1]);
795         if ( param[0]!='-' )
796             fnameToOpen = param;
797     }
798     if ( fnameToOpen == U"test_format" ) {
799         testFormatting();
800     }
801 
802 #ifdef _WIN32
803     //::GetSystemMetrics()
804     RECT wrc;
805     SystemParametersInfo( SPI_GETWORKAREA, 0, &wrc, 0 );
806     int x = wrc.left;
807     int y = wrc.top;
808     int cx = wrc.right - wrc.left;
809     int cy = wrc.bottom - wrc.top;
810 #else
811     int x = 20;
812     int y = 40;
813     int cx = wxSystemSettings::GetMetric( wxSYS_SCREEN_X );
814     int cy = wxSystemSettings::GetMetric( wxSYS_SCREEN_Y )-40;
815 #endif
816     int scale_x = cx * 256 / 620;
817     int scale_y = cy * 256 / 830;
818     int scale = scale_x < scale_y ? scale_x : scale_y;
819     cx = 610 * scale / 256;
820     cy = 830 * scale / 256;
821     cr3Frame *frame = new cr3Frame( wxT( "CoolReader " wxT(CR3_VERSION) ), wxPoint(x,y), wxSize(cx,cy), appPath );
822 
823 
824 
825     frame->Show(TRUE);
826     SetTopWindow(frame);
827     return TRUE;
828 }
829 
UpdateToolbar()830 void cr3Frame::UpdateToolbar()
831 {
832     if ( _toolbarSize==0 )
833         return;
834     bool enabled_book = _activeMode==am_book && _view->getDocView()->isDocumentOpened();
835     wxToolBar* toolBar = GetToolBar();
836     toolBar->EnableTool(wxID_SAVE, enabled_book);
837     toolBar->EnableTool(Menu_View_ZoomIn, enabled_book);
838     toolBar->EnableTool(Menu_View_ZoomOut, enabled_book);
839     toolBar->EnableTool(Menu_View_TOC, enabled_book);
840     toolBar->EnableTool(Menu_View_Rotate, enabled_book);
841     toolBar->EnableTool(Menu_View_TogglePages, enabled_book);
842     toolBar->EnableTool(Menu_View_PrevPage, enabled_book);
843     toolBar->EnableTool(Menu_View_NextPage, enabled_book);
844 }
845 
SetActiveMode(active_mode_t mode)846 void cr3Frame::SetActiveMode( active_mode_t mode )
847 {
848     if ( mode==_activeMode )
849         return;
850     switch (mode) {
851     case am_book:
852         {
853             _sizer->Show(_view, true);
854             _sizer->Show(_scrollBar, true);
855             _sizer->Show(_hist, false);
856             _sizer->Layout();
857             //_hist->Show(false);
858             //SetSizer( _sizer, false );
859             //_view->Show(true);
860             //_scrollBar->Show(true);
861             _view->SetFocus();
862         }
863         break;
864     case am_history:
865         {
866             _sizer->Show(_view, false);
867             _sizer->Show(_scrollBar, false);
868             _sizer->Show(_hist, true);
869             _sizer->Layout();
870 
871             //_histsizer->Show();
872             //_sizer->Hide();
873             //_view->Show(false);
874             //_scrollBar->Show(false);
875             //SetSizer( _histsizer, false );
876             //_hist->Show(true);
877             //_histsizer->Layout();
878             _view->getDocView()->savePosition();
879             _hist->SetRecords(_view->getDocView()->getHistory()->getRecords());
880             _sizer->Layout();
881             _hist->UpdateColumns();
882             _hist->SetFocus();
883         }
884         break;
885     default:
886         break;
887     }
888     _activeMode = mode;
889     UpdateToolbar();
890 }
891 
SetMenu(bool visible)892 void cr3Frame::SetMenu( bool visible )
893 {
894     bool was_visible = (GetMenuBar()!=NULL);
895     if ( was_visible == visible )
896         return;
897     if ( !visible ) {
898         SetMenuBar(NULL);
899         return;
900     }
901     wxMenu *menuFile = new wxMenu;
902 
903     menuFile->Append( wxID_OPEN, wxT( "&Open...\tCtrl+O" ) );
904     menuFile->Append( Menu_View_History, wxT( "Recent books list\tF4" ) );
905     menuFile->Append( wxID_SAVE, wxT( "&Save...\tCtrl+S" ) );
906     menuFile->AppendSeparator();
907     menuFile->Append( Menu_File_Options, wxT( "&Options...\tF9" ) );
908     menuFile->AppendSeparator();
909     menuFile->Append( Menu_File_About, wxT( "&About...\tF1" ) );
910     menuFile->AppendSeparator();
911     menuFile->Append( Menu_File_Quit, wxT( "E&xit\tAlt+X" ) );
912 
913     wxMenu *menuView = new wxMenu;
914 
915     menuView->Append( Menu_View_TOC, wxT( "Table of Contents\tF5" ) );
916     menuView->Append( Menu_View_History, wxT( "Recent Books\tF4" ) );
917     menuView->Append( Menu_View_Rotate, wxT( "Rotate\tCtrl+R" ) );
918 
919     menuView->AppendSeparator();
920     menuView->Append( Menu_View_ZoomIn, wxT( "Zoom In" ) );
921     menuView->Append( Menu_View_ZoomOut, wxT( "Zoom Out" ) );
922     menuView->AppendSeparator();
923     menuView->Append( Menu_View_ToggleFullScreen, wxT( "Toggle Fullscreen\tAlt+Enter" ) );
924     menuView->Append( Menu_View_TogglePages, wxT( "Toggle Pages/Scroll\tCtrl+P" ) );
925     menuView->Append( Menu_View_TogglePageHeader, wxT( "Toggle page heading\tCtrl+H" ) );
926 
927     wxMenuBar *menuBar = new wxMenuBar;
928     menuBar->Append( menuFile, wxT( "&File" ) );
929     menuBar->Append( menuView, wxT( "&View" ) );
930 
931     SetMenuBar( menuBar );
932 }
933 
934 
SetStatus(bool visible)935 void cr3Frame::SetStatus( bool visible )
936 {
937     bool was_visible = (GetStatusBar()!=NULL);
938     if ( was_visible == visible )
939         return;
940     if ( !visible ) {
941         SetStatusBar(NULL);
942         return;
943     }
944     CreateStatusBar();
945     wxStatusBar * status = GetStatusBar();
946     int sw[3] = { -1, 100, 100 };
947     //int ss[3] = {wxSB_NORMAL, wxSB_FLAT, wxSB_FLAT};
948     status->SetFieldsCount(2, sw);
949     //status->SetStatusStyles(3, ss);
950     SetStatusText( wxT( "Welcome to CoolReader " wxT(CR3_VERSION) wxT("!") ) );
951 }
952 
953 
954 static const long TOOLBAR_STYLE = wxTB_FLAT | wxTB_DOCKABLE; // | wxTB_TEXT // | wxTB_DOCKABLE
955 
SetToolbarSize(int size)956 void cr3Frame::SetToolbarSize( int size )
957 {
958     //if ( size == _toolbarSize )
959     //    return;
960     _toolbarSize = size;
961     if ( !_toolbarSize ) {
962         SetToolBar(NULL);
963         return;
964     }
965 
966     wxToolBar* toolBar = GetToolBar();
967 
968     long style = toolBar ? toolBar->GetWindowStyle() : TOOLBAR_STYLE;
969     delete toolBar;
970     SetToolBar(NULL);
971     style &= ~(wxTB_HORIZONTAL | wxTB_VERTICAL | wxTB_BOTTOM | wxTB_RIGHT | wxTB_HORZ_LAYOUT);
972     int mode = _props->getIntDef( PROP_WINDOW_TOOLBAR_POSITION, 0 );
973     switch ( mode ) {
974     case 1:
975         style |= wxTB_LEFT;
976         break;
977     default:
978         style |= wxTB_TOP;
979         break;
980     case 2:
981         style |= wxTB_RIGHT;
982         break;
983     case 3:
984         style |= wxTB_BOTTOM;
985         break;
986     }
987     //style |= wxTB_NO_TOOLTIPS;
988     toolBar = CreateToolBar(style, wxID_ANY);
989     /*
990     if ( toolBar == NULL ) {
991         toolBar = CreateToolBar();
992     } else {
993         int ids[] = {
994             wxID_OPEN,
995             Menu_View_History,
996             wxID_SAVE,
997             Menu_View_ZoomIn,
998             Menu_View_ZoomOut,
999             Menu_View_TOC,
1000             Menu_View_TogglePages,
1001             Menu_View_ToggleFullScreen,
1002             Menu_View_PrevPage,
1003             Menu_View_NextPage,
1004             Menu_File_Options,
1005             Menu_File_About,
1006             -1
1007         };
1008         for ( int i=0; ids[i]!=-1; i++ ) {
1009             toolBar->DeleteTool(ids[i]);
1010         }
1011     }
1012     */
1013 
1014     wxBitmap fileopenBitmap = getIcon16x16(U"fileopen");
1015 
1016     int w = fileopenBitmap.GetWidth(),
1017         h = fileopenBitmap.GetHeight();
1018 
1019 
1020 
1021     toolBar->SetToolBitmapSize(wxSize(w, h));
1022 /*
1023     toolBar->AddTool(wxID_NEW, _T("New"),
1024                      toolBarBitmaps[Tool_new], wxNullBitmap, wxITEM_NORMAL,
1025                      _T("New file"), _T("This is help for new file tool"));
1026 */
1027     toolBar->AddTool(wxID_OPEN, _T("Open"),
1028                      fileopenBitmap,//toolBarBitmaps[Tool_open],
1029                      wxNullBitmap, wxITEM_NORMAL,
1030                      _T("Open file"), _T("This is help for open file tool"));
1031     toolBar->AddTool(Menu_View_History, _T("History (F5)"),
1032                      getIcon16x16(U"project_open"),//toolBarBitmaps[Tool_open],
1033                      wxNullBitmap, wxITEM_NORMAL,
1034                      _T("Toggle recent books list"), _T("Toggle recent opened books list"));
1035 
1036     toolBar->AddTool(wxID_SAVE, _T("Save"),
1037                      getIcon16x16(U"filesaveas"),//toolBarBitmaps[Tool_save],
1038                      wxNullBitmap, wxITEM_NORMAL,
1039                      _T("Save as..."), _T("Export document"));
1040 
1041     toolBar->AddSeparator();
1042     toolBar->AddTool(Menu_View_ZoomIn, _T("Zoom In"),
1043                      getIcon16x16(U"viewmag+"),//toolBarBitmaps[Tool_zoomin],
1044                      wxNullBitmap, wxITEM_NORMAL,
1045                      _T("Zoom in"), _T("Increase font size"));
1046     toolBar->AddTool(Menu_View_ZoomOut, _T("Zoom Out"),
1047                      getIcon16x16(U"viewmag-"),//toolBarBitmaps[Tool_zoomout],
1048                      wxNullBitmap, wxITEM_NORMAL,
1049                      _T("Zoom out"), _T("Decrease font size"));
1050     toolBar->AddTool(Menu_View_Rotate, _T("Rotate (Ctrl+R)"),
1051                      getIcon16x16(U"rotate_cw"),//toolBarBitmaps[Tool_zoomout],
1052                      wxNullBitmap, wxITEM_NORMAL,
1053                      _T("Rotate (Ctrl+R)"), _T("Rotate text clockwise"));
1054     toolBar->AddSeparator();
1055     toolBar->AddTool(Menu_View_TOC, _T("Table of Contents (F5)"),
1056                      getIcon16x16(U"player_playlist"),//toolBarBitmaps[Tool_zoomout],
1057                      wxNullBitmap, wxITEM_NORMAL,
1058                      _T("Table of Contents (F5)"), _T("Show Table of Contents window"));
1059     toolBar->AddTool(Menu_View_TogglePages, _T("Toggle pages (Ctrl+P)"),
1060                      getIcon16x16(U"view_left_right"),//toolBarBitmaps[Tool_zoomout],
1061                      wxNullBitmap, wxITEM_NORMAL,
1062                      _T("Toggle pages (Ctrl+P)"), _T("Switch pages/scroll mode"));
1063     toolBar->AddTool(Menu_View_ToggleFullScreen, _T("Fullscreen (Alt+Enter)"),
1064                      getIcon16x16(U"window_fullscreen"),//toolBarBitmaps[Tool_zoomout],
1065                      wxNullBitmap, wxITEM_NORMAL,
1066                      _T("Fullscreen (Alt+Enter)"), _T("Switch to fullscreen mode"));
1067     toolBar->AddSeparator();
1068 //Menu_View_ToggleFullScreen
1069     toolBar->AddTool(Menu_View_PrevPage, _T("Previous page"),
1070                      getIcon16x16(U"previous"),//toolBarBitmaps[Tool_north],
1071                      wxNullBitmap, wxITEM_NORMAL,
1072                      _T("Previous page"), _T("Go to previous page"));
1073     toolBar->AddTool(Menu_View_NextPage, _T("Next page"),
1074                      getIcon16x16(U"next"),//toolBarBitmaps[Tool_south],
1075                      wxNullBitmap, wxITEM_NORMAL,
1076                      _T("Next page"), _T("Go to next page"));
1077 
1078     toolBar->AddSeparator();
1079     toolBar->AddTool(Menu_File_Options, _T("Options"), //wxID_HELP
1080                      getIcon16x16(U"configure"),//toolBarBitmaps[Tool_help],
1081                      wxNullBitmap, wxITEM_NORMAL,
1082                      _T("Options (F9)"), _T("Options (F9)"));
1083     toolBar->AddSeparator();
1084     toolBar->AddTool(Menu_File_About, _T("Help"), //wxID_HELP
1085                      getIcon16x16(U"help"),//toolBarBitmaps[Tool_help],
1086                      wxNullBitmap, wxITEM_NORMAL,
1087                      _T("Help"), _T("Help"));
1088 
1089     // after adding the buttons to the toolbar, must call Realize() to reflect
1090     // the changes
1091     toolBar->Realize();
1092 }
1093 
OnInitDialog(wxInitDialogEvent & event)1094 void cr3Frame::OnInitDialog(wxInitDialogEvent& event)
1095 {
1096     _scrollBar = new cr3scroll(_view);
1097 
1098     _view->SetScrollBar( _scrollBar );
1099     _view->Create(this, Window_Id_View,
1100         wxDefaultPosition, wxDefaultSize, 0, wxT("cr3view"));
1101     _hist->Create(this, Window_Id_HistList);
1102 
1103     _scrollBar->Create(this, Window_Id_Scrollbar,
1104         wxDefaultPosition, wxDefaultSize, wxSB_VERTICAL);
1105 
1106 
1107     wxIcon icon = wxICON(cr3);
1108     SetIcon( icon );
1109 
1110     //SetMenu( true );
1111 
1112     //SetStatus( true );
1113 
1114     //SetToolbarSize( 3 );
1115 
1116 
1117     //_histsizer = new wxBoxSizer( wxHORIZONTAL );
1118 
1119     _sizer = new wxBoxSizer( wxHORIZONTAL );
1120     _sizer->Add( _view,
1121         1,
1122         wxALL | wxEXPAND,
1123         0);
1124     _sizer->Add( _scrollBar,
1125         0,
1126         wxALIGN_RIGHT | wxEXPAND,
1127         0);
1128     _sizer->Add( _hist,
1129         1,
1130         wxALL | wxEXPAND,
1131         0);
1132 
1133     SetSizer( _sizer );
1134 
1135     _view->SetBackgroundColour( _view->getBackgroundColour() );
1136     //_scrollBar->Show( true );
1137     SetBackgroundColour( _view->getBackgroundColour() );
1138 
1139     // stylesheet can be placed to file fb2.css
1140     // if not found, default stylesheet will be used
1141     //char cssfn[1024];
1142     //sprintf( cssfn, "fb2.css"); //, exedir
1143     //lString8 css = readFileToString( (UnicodeToLocal(_appDir) + cssfn).c_str() );
1144     lString8 css;
1145     LVLoadStylesheetFile( _appDir + "fb2.css", css );
1146 #ifdef _LINUX
1147     if ( css.empty() )
1148         LVLoadStylesheetFile( U"/usr/share/cr3/fb2.css", css );
1149         //css = readFileToString( "/usr/share/crengine/fb2.css" );
1150     if ( css.empty() )
1151         LVLoadStylesheetFile( U"/usr/local/share/cr3/fb2.css", css );
1152         //css = readFileToString( "/usr/local/share/crengine/fb2.css" );
1153 #endif
1154     if (css.length() > 0)
1155     {
1156         printf("Style sheet file found.\n");
1157         _view->getDocView()->setStyleSheet( css );
1158     }
1159 
1160     wxAcceleratorEntry entries[40];
1161     int a=0;
1162     entries[a++].Set(wxACCEL_CTRL,  (int) 'O',     wxID_OPEN);
1163     entries[a++].Set(wxACCEL_CTRL,  (int) 'S',     wxID_SAVE);
1164     entries[a++].Set(wxACCEL_CTRL,  (int) 'P',     Menu_View_TogglePages);
1165     entries[a++].Set(wxACCEL_CTRL,  (int) 'H',     Menu_View_TogglePageHeader);
1166     entries[a++].Set(wxACCEL_CTRL,  (int) 'R',     Menu_View_Rotate);
1167     entries[a++].Set(wxACCEL_NORMAL,  WXK_F3,      wxID_OPEN);
1168     entries[a++].Set(wxACCEL_NORMAL,  WXK_F2,      wxID_SAVE);
1169     entries[a++].Set(wxACCEL_NORMAL,  WXK_UP,      Menu_View_PrevLine);
1170     entries[a++].Set(wxACCEL_NORMAL,  WXK_DOWN,    Menu_View_NextLine);
1171     entries[a++].Set(wxACCEL_NORMAL,  WXK_SPACE,    Menu_View_NextLine);
1172     entries[a++].Set(wxACCEL_NORMAL,  WXK_NUMPAD_ADD,      Menu_View_ZoomIn);
1173     entries[a++].Set(wxACCEL_NORMAL,  WXK_NUMPAD_SUBTRACT, Menu_View_ZoomOut);
1174     entries[a++].Set(wxACCEL_NORMAL,  WXK_ADD,      Menu_View_ZoomIn);
1175     entries[a++].Set(wxACCEL_NORMAL,  WXK_SUBTRACT, Menu_View_ZoomOut);
1176     entries[a++].Set(wxACCEL_CTRL,    WXK_NUMPAD_ADD,      Menu_View_ZoomIn);
1177     entries[a++].Set(wxACCEL_CTRL,    WXK_NUMPAD_SUBTRACT, Menu_View_ZoomOut);
1178     entries[a++].Set(wxACCEL_NORMAL,  (int) '+',     Menu_View_ZoomIn);
1179     entries[a++].Set(wxACCEL_NORMAL,  (int) '-',     Menu_View_ZoomOut);
1180     entries[a++].Set(wxACCEL_NORMAL,  (int) '=',     Menu_View_ZoomIn);
1181     entries[a++].Set(wxACCEL_NORMAL,  WXK_PAGEUP,    Menu_View_PrevPage);
1182     entries[a++].Set(wxACCEL_NORMAL,  WXK_PAGEDOWN,  Menu_View_NextPage);
1183     entries[a++].Set(wxACCEL_NORMAL,  WXK_HOME,      Menu_View_Begin);
1184     entries[a++].Set(wxACCEL_NORMAL,  WXK_END,       Menu_View_End);
1185     entries[a++].Set(wxACCEL_CTRL,    (int) 'T',     Menu_View_Text_Format);
1186     entries[a++].Set(wxACCEL_ALT,     WXK_RETURN,     Menu_View_ToggleFullScreen);
1187     entries[a++].Set(wxACCEL_NORMAL,  WXK_F5,      Menu_View_TOC);
1188     entries[a++].Set(wxACCEL_NORMAL,  WXK_F4,      Menu_View_History);
1189 
1190     entries[a++].Set(wxACCEL_NORMAL,  WXK_F9,      Menu_File_Options);
1191     entries[a++].Set(wxACCEL_NORMAL,  WXK_F12,      Menu_File_Quit);
1192     entries[a++].Set(wxACCEL_NORMAL,  WXK_BACK,      Menu_Link_Back);
1193     entries[a++].Set(wxACCEL_SHIFT,   WXK_BACK,      Menu_Link_Forward);
1194     entries[a++].Set(wxACCEL_NORMAL,  WXK_TAB,      Menu_Link_Next);
1195     entries[a++].Set(wxACCEL_NORMAL,  WXK_RETURN,      Menu_Link_Go);
1196     entries[a++].Set(wxACCEL_SHIFT,   WXK_TAB,      Menu_Link_Prev);
1197 
1198     wxAcceleratorTable accel(a, entries);
1199     SetAcceleratorTable(accel);
1200     //_view->SetAcceleratorTable(accel);
1201 
1202 
1203     //toolBar->SetRows(!(toolBar->IsVertical()) ? m_rows : 10 / m_rows);
1204     int argc = wxGetApp().argc;
1205     lString32 fnameToOpen;
1206     lString32 formatName;
1207     lString32 outFile;
1208     bool convert = false;
1209     for ( int i=1; i<argc; i++ ) {
1210         lString32 param = wx2cr(wxGetApp().argv[i]);
1211         if ( param[0]!='-' )
1212             fnameToOpen = param;
1213         else if (param.startsWith("--convert"))
1214             convert = true;
1215         else if (param.startsWith("--format=")) {
1216             formatName = param.substr(9);
1217         } else if (param.startsWith("--out=")) {
1218             outFile = param.substr(6);
1219         }
1220     }
1221     if ( fnameToOpen == U"test_format" ) {
1222         testFormatting();
1223     }
1224     if ( !fnameToOpen.empty() && convert  ) {
1225         if ( formatName.empty() )
1226             formatName = U"wol";
1227         //==U"wol"
1228         if ( outFile.empty() )
1229             outFile = fnameToOpen + ".wol";
1230         // convertor
1231         if ( !_view->LoadDocument( cr2wx(fnameToOpen) ) )
1232             exit(1);
1233         if ( !_view->getDocView()->exportWolFile( outFile.c_str(), true, 3 ) )
1234             exit(2);
1235         // no errors
1236         exit(0);
1237     }
1238     if ( fnameToOpen.empty() ) {
1239         fnameToOpen = _view->GetLastRecentFileName();
1240     }
1241 
1242     if ( !fnameToOpen.empty() && fnameToOpen[0]=='\"' )
1243         fnameToOpen.erase(0, 1);
1244     if ( !fnameToOpen.empty() && fnameToOpen[fnameToOpen.length()-1]=='\"' )
1245         fnameToOpen.erase(fnameToOpen.length()-1, 1);
1246     if ( fnameToOpen == U"test_format" ) {
1247         testFormatting();
1248         Destroy();
1249         return;
1250     }
1251 
1252     _view->Show( true );
1253     //_view->UpdateScrollBar();
1254 
1255     RestoreOptions();
1256     if ( !fnameToOpen.empty() ) {
1257         if ( !_view->LoadDocument( cr2wx(fnameToOpen) ) )
1258         {
1259             printf("cannot open document\n");
1260         }
1261         SetActiveMode( am_book );
1262         UpdateToolbar();
1263     } else {
1264         SetActiveMode( am_history );
1265     }
1266 
1267     //Show();
1268 }
1269 
1270 
cr3Frame(const wxString & title,const wxPoint & pos,const wxSize & size,lString32 appDir)1271 cr3Frame::cr3Frame(const wxString& title, const wxPoint& pos, const wxSize& size, lString32 appDir )
1272     : wxFrame((wxFrame *)NULL, -1, title, pos, size), _activeMode(am_none), _toolbarSize(false)
1273 {
1274     //wxStandardPaths::GetUserDataDir();
1275 
1276     _props = LVCreatePropsContainer();
1277 
1278 
1279 
1280     _appDir = appDir;
1281 
1282     _isFullscreen = false;
1283 
1284     {
1285         // load options from file
1286         LVStreamRef stream = LVOpenFileStream( GetConfigFileName().c_str(), LVOM_READ );
1287         if ( !stream.isNull() )
1288             _props->loadFromStream(stream.get());
1289     }
1290 
1291     _view = new cr3view( _props, appDir );
1292     _hist = new HistList();
1293 
1294     InitDialog();
1295 }
1296 
SaveOptions()1297 void cr3Frame::SaveOptions()
1298 {
1299     //_props->setHex(PROP_FONT_COLOR, _view->getDocView()->getTextColor() );
1300     //_props->setHex(PROP_BACKGROUND_COLOR, _view->getDocView()->getBackgroundColor() );
1301     _props->setInt(PROP_CRENGINE_FONT_SIZE, _view->getDocView()->getFontSize() );
1302     _props->setBool(PROP_WINDOW_FULLSCREEN, _isFullscreen );
1303     bool maximized = IsMaximized();
1304     bool minimized = IsIconized();
1305     _props->setBool(PROP_WINDOW_MAXIMIZED, maximized );
1306     _props->setBool(PROP_WINDOW_MINIMIZED, minimized );
1307     if ( !minimized && !maximized && !_isFullscreen ) {
1308         wxRect rc = GetRect();
1309         lvRect lvrc( rc.GetLeft(), rc.GetTop(), rc.GetRight(), rc.GetBottom() );
1310         _props->setRect(PROP_WINDOW_RECT, lvrc );
1311     }
1312     {
1313         // save options to file
1314         LVStreamRef stream = LVOpenFileStream( GetConfigFileName().c_str(), LVOM_WRITE );
1315         if ( !stream.isNull() )
1316             _props->saveToStream(stream.get());
1317     }
1318 }
1319 
RestoreOptions()1320 void cr3Frame::RestoreOptions()
1321 {
1322     if ( !_isFullscreen ) {
1323         SetMenu( _props->getBoolDef(PROP_WINDOW_SHOW_MENU, true) );
1324         SetStatus( _props->getBoolDef(PROP_WINDOW_SHOW_STATUSBAR, true) );
1325         int tb = _props->getIntDef(PROP_WINDOW_TOOLBAR_SIZE, 2);
1326         if ( tb<0 )
1327             tb = 0;
1328         if ( tb>3)
1329             tb = 3;
1330         SetToolbarSize( tb );
1331         lvRect lvrc;
1332         if ( _props->getRect(PROP_WINDOW_RECT, lvrc ) ) {
1333             wxRect rc( lvrc.left, lvrc.top, lvrc.width(), lvrc.height() );
1334             SetSize( rc );
1335         }
1336         if ( _props->getBoolDef(PROP_WINDOW_MAXIMIZED) )
1337             Maximize();
1338         else if ( _props->getBoolDef(PROP_WINDOW_MINIMIZED) )
1339             Iconize();
1340     }
1341     fontMan->SetAntialiasMode( _props->getIntDef( PROP_FONT_ANTIALIASING, 2 ) );
1342     _view->getDocView()->setDefaultFontFace( UnicodeToUtf8(_props->getStringDef(PROP_FONT_FACE, "Arial" )) );
1343     _view->getDocView()->setTextColor( _props->getIntDef(PROP_FONT_COLOR, 0x000060 ) );
1344     _view->getDocView()->setBackgroundColor( _props->getIntDef(PROP_BACKGROUND_COLOR, 0xFFFFE0 ) );
1345     _view->getDocView()->setFontSize( _props->getIntDef( PROP_CRENGINE_FONT_SIZE, 28 ) );
1346     _view->SetPageHeaderFlags();
1347 
1348     //_view->SetPageHeaderFlags();
1349 
1350     int mode = _props->getIntDef( PROP_PAGE_VIEW_MODE, 2 );
1351     _view->getDocView()->setViewMode( mode>0 ? DVM_PAGES : DVM_SCROLL, mode>0 ? mode : -1 );
1352 
1353     if ( _props->getBoolDef(PROP_WINDOW_FULLSCREEN) != _isFullscreen ) {
1354         _isFullscreen = !_isFullscreen;
1355         if ( _isFullscreen )
1356             Show();
1357         ShowFullScreen( _isFullscreen );
1358     }
1359 }
1360 
1361 void
OnQuit(wxCommandEvent & WXUNUSED (event))1362 cr3Frame::OnQuit( wxCommandEvent& WXUNUSED( event ) )
1363 {
1364     //SaveOptions();
1365     Close(TRUE);
1366 }
1367 
1368 void
OnShowHistory(wxCommandEvent & event)1369 cr3Frame::OnShowHistory( wxCommandEvent& event )
1370 {
1371     switch ( _activeMode ) {
1372     case am_book:
1373         SetActiveMode( am_history );
1374         break;
1375     case am_history:
1376         SetActiveMode( am_book );
1377         break;
1378     default:
1379 	break;
1380     }
1381 }
1382 
OnOptionsChange(CRPropRef oldprops,CRPropRef newprops,CRPropRef changed)1383 void cr3Frame::OnOptionsChange( CRPropRef oldprops, CRPropRef newprops, CRPropRef changed )
1384 {
1385     if ( changed->getCount()>0 ) {
1386         _props->set( newprops );
1387         SaveOptions();
1388         RestoreOptions();
1389     }
1390     ///
1391 }
1392 
1393 void
OnShowOptions(wxCommandEvent & event)1394 cr3Frame::OnShowOptions( wxCommandEvent& event )
1395 {
1396     CR3OptionsDialog dlg(_props);
1397     dlg.Create( this, Window_Id_Options );
1398     if ( dlg.ShowModal() == wxID_OK ) {
1399         // set options
1400         dlg.ControlsToProps();
1401         OnOptionsChange( dlg.getOldProps(), dlg.getNewProps(), dlg.getChangedProps() );
1402     }
1403 }
1404 
1405 void
OnRotate(wxCommandEvent & event)1406 cr3Frame::OnRotate( wxCommandEvent& event )
1407 {
1408     _view->Rotate();
1409     SaveOptions();
1410 }
1411 
1412 void
OnShowTOC(wxCommandEvent & event)1413 cr3Frame::OnShowTOC( wxCommandEvent& event )
1414 {
1415     LVTocItem * toc = _view->getDocView()->getToc();
1416     ldomXPointer pos = _view->getDocView()->getBookmark();
1417     if ( !toc || !toc->getChildCount() )
1418         return;
1419     TocDialog dlg( this, toc, _view->getDocView()->getTitle(), pos );
1420     if ( dlg.ShowModal() == wxID_OK ) {
1421         // go to
1422         LVTocItem * sel = dlg.getSelection();
1423         if ( sel ) {
1424             ldomXPointer ptr = sel->getXPointer();
1425             _view->goToBookmark( ptr );
1426             Update();
1427         }
1428     }
1429 }
1430 
1431 
1432 void
OnFileOpen(wxCommandEvent & WXUNUSED (event))1433 cr3Frame::OnFileOpen( wxCommandEvent& WXUNUSED( event ) )
1434 {
1435     wxFileDialog dlg( this, wxT( "Choose a file to open" ),
1436         wxT( "" ),
1437         wxT( "" ),//const wxString& defaultFile = "",
1438         wxT("All supported files|*.fb2;*.fbz;*.txt;*.zip;*.rtf;*.epub;*.tcr;*.html;*.htm;*.shtml;*.xhtml|FictionBook files (*.fb2)|*.fb2;*.fbz|RTF files (*.rtf)|*.rtf|Text files (*.txt, *.tcr)|*.txt;*.tcr|HTML files|*.html;*.htm;*.shtml;*.xhtml|EPUB files (*.epub)|*.epub|ZIP archieves (*.zip)|*.zip"), //const wxString& wildcard = "*.*",
1439         wxFD_OPEN | wxFD_FILE_MUST_EXIST //long style = wxFD_DEFAULT_STYLE,
1440         //const wxPoint& pos = wxDefaultPosition,
1441         //const wxSize& sz = wxDefaultSize,
1442         //const wxString& name = "filedlg"
1443     );
1444 
1445     if ( dlg.ShowModal() == wxID_OK ) {
1446         //
1447         Update();
1448         SetActiveMode( am_book );
1449         wxCursor hg( wxCURSOR_WAIT );
1450         this->SetCursor( hg );
1451         wxSetCursor( hg );
1452         _view->getDocView()->savePosition();
1453         _view->LoadDocument( dlg.GetPath() );
1454         _view->getDocView()->restorePosition();
1455         _view->UpdateScrollBar();
1456         //Invalidate();
1457         Refresh();
1458         Update();
1459         UpdateToolbar();
1460         wxSetCursor( wxNullCursor );
1461         this->SetCursor( wxNullCursor );
1462     }
1463 
1464 }
1465 
1466 void
OnFileSave(wxCommandEvent & WXUNUSED (event))1467 cr3Frame::OnFileSave( wxCommandEvent& WXUNUSED( event ) )
1468 {
1469     wxFileDialog dlg( this, wxT( "Choose a file to open" ),
1470         wxT( "" ),
1471         wxT( "" ),//const wxString& defaultFile = "",
1472         wxT("Wolf EBook files (*.wol)|*.wol"), //const wxString& wildcard = "*.*",
1473         wxFD_SAVE | wxFD_OVERWRITE_PROMPT //long style = wxFD_DEFAULT_STYLE,
1474         //const wxPoint& pos = wxDefaultPosition,
1475         //const wxSize& sz = wxDefaultSize,
1476         //const wxString& name = "filedlg"
1477     );
1478     WolOptions opts( this );
1479     if ( dlg.ShowModal() == wxID_OK && opts.ShowModal() == wxID_OK ) {
1480         //
1481         //_view->LoadDocument( dlg.GetPath() );
1482         Refresh();
1483         Update();
1484         wxCursor hg( wxCURSOR_WAIT );
1485         this->SetCursor( hg );
1486         wxSetCursor( hg );
1487         _view->getDocView()->exportWolFile( wx2cr(dlg.GetPath()).c_str(), opts.getMode()==0, opts.getLevels() );
1488         wxSetCursor( wxNullCursor );
1489         this->SetCursor( wxNullCursor );
1490     }
1491 }
1492 
1493 void
OnAbout(wxCommandEvent & WXUNUSED (event))1494 cr3Frame::OnAbout( wxCommandEvent& WXUNUSED( event ) )
1495 {
1496     wxMessageBox( wxT( "Cool Reader " wxT(CR3_VERSION) wxT("\n(c) 1998-2018 Vadim Lopatin\n" wxVERSION_STRING"\n") )
1497     wxT("\nBased on CREngine library " wxT(CR_ENGINE_VERSION) )
1498     wxT("\nThird party libraries used:")
1499     wxT("\nzlib, libpng, libjpeg, freetype2,")
1500     wxT("\nhyphenation library by Alan")
1501     wxT("\n")
1502     wxT("\nThe program is being distributed under the terms of GNU General Public License")
1503     wxT("\nproject homepage is http://www.coolreader.org/crengine.htm")
1504     wxT("\nsource codes are available at http://sourceforge.net/projects/crengine"
1505     ),
1506             wxT( "About Cool Reader" ), wxOK | wxICON_INFORMATION, this );
1507 }
1508 
1509 void
OnScroll(wxScrollEvent & event)1510 cr3Frame::OnScroll(wxScrollEvent& event)
1511 {
1512     _view->OnScroll( event );
1513 }
1514 
OnSetFocus(wxFocusEvent & event)1515 void cr3scroll::OnSetFocus( wxFocusEvent& event )
1516 {
1517     _view->SetFocus();
1518 }
1519 
OnSetFocus(wxFocusEvent & event)1520 void cr3view::OnSetFocus( wxFocusEvent& event )
1521 {
1522     GetParent()->SetFocus();
1523 }
1524 
1525 void
OnKeyDown(wxKeyEvent & event)1526 cr3Frame::OnKeyDown(wxKeyEvent& event)
1527 {
1528     if ( _activeMode==am_book )
1529         _view->OnKeyDown( event );
1530     else
1531         event.Skip();
1532 }
1533