1 /* This file is (c) 2008-2012 Konstantin Isakov <ikm@goldendict.org>
2  * Part of GoldenDict. Licensed under GPLv3 or later, see the LICENSE file */
3 
4 #ifndef __ARTICLE_MAKER_HH_INCLUDED__
5 #define __ARTICLE_MAKER_HH_INCLUDED__
6 
7 #include <QObject>
8 #include <QMap>
9 #include <set>
10 #include <list>
11 #include "dictionary.hh"
12 #include "instances.hh"
13 #include "wordfinder.hh"
14 
15 /// This class generates the article's body for the given lookup request
16 class ArticleMaker: public QObject
17 {
18   Q_OBJECT // We make it QObject to use tr() conveniently
19 
20   std::vector< sptr< Dictionary::Class > > const & dictionaries;
21   std::vector< Instances::Group > const & groups;
22 
23   QString displayStyle, addonStyle;
24 
25   bool needExpandOptionalParts;
26   bool collapseBigArticles;
27   int articleLimitSize;
28 
29 public:
30 
31   /// On construction, a reference to all dictionaries and a reference all
32   /// groups' instances are to be passed. Those references are kept stored as
33   /// references, and as such, any changes to them would reflect on the results
34   /// of the inquiries, although those changes are perfectly legal.
35   ArticleMaker( std::vector< sptr< Dictionary::Class > > const & dictionaries,
36                 std::vector< Instances::Group > const & groups,
37                 QString const & displayStyle,
38                 QString const & addonStyle);
39 
40   /// Sets the display style to use for any new requests. This affects the
41   /// choice of the stylesheet file.
42   void setDisplayStyle( QString const &, QString const & addonStyle );
43 
44   /// Looks up the given word within the given group, and creates a full html
45   /// page text containing its definition.
46   /// The result is returned as Dictionary::DataRequest just like dictionaries
47   /// themselves do. The difference is that the result is a complete html page
48   /// with all definitions from all the relevant dictionaries.
49   /// Contexts is a map of context values to be passed to each dictionary, where
50   /// the keys are dictionary ids.
51   /// If mutedDicts is not empty, the search would be limited only to those
52   /// dictionaries in group which aren't listed there.
53   sptr< Dictionary::DataRequest > makeDefinitionFor( QString const & word, unsigned groupId,
54                                                      QMap< QString, QString > const & contexts,
55                                                      QSet< QString > const & mutedDicts =
56                                                        QSet< QString >(),
57                                                      QStringList const & dictIDs = QStringList(),
58                                                      bool ignoreDiacritics = false ) const;
59 
60   /// Makes up a text which states that no translation for the given word
61   /// was found. Sometimes it's better to call this directly when it's already
62   /// known that there's no translation.
63   sptr< Dictionary::DataRequest > makeNotFoundTextFor( QString const & word, QString const & group ) const;
64 
65   /// Creates an 'untitled' page. The result is guaranteed to be instant.
66   sptr< Dictionary::DataRequest > makeEmptyPage() const;
67 
68   /// Create page with one picture
69   sptr< Dictionary::DataRequest > makePicturePage( std::string const & url ) const;
70 
71   /// Set auto expanding optional parts of articles
72   void setExpandOptionalParts( bool expand );
73 
74   /// Add base path to file path if it's relative and file not found
75   /// Return true if path successfully adjusted
76   static bool adjustFilePath( QString & fileName );
77 
78   /// Set collapse articles parameters
79   void setCollapseParameters( bool autoCollapse, int articleSize );
80 
81 private:
82 
83   /// Makes everything up to and including the opening body tag.
84   std::string makeHtmlHeader( QString const & word, QString const & icon,
85                               bool expandOptionalParts ) const;
86 
87   /// Makes the html body for makeNotFoundTextFor()
88   static std::string makeNotFoundBody( QString const & word, QString const & group );
89 
90   friend class ArticleRequest; // Allow it calling makeNotFoundBody()
91 };
92 
93 /// The request specific to article maker. This should really be private,
94 /// but we need it to be handled by moc.
95 class ArticleRequest: public Dictionary::DataRequest
96 {
97   Q_OBJECT
98 
99   QString word, group;
100   QMap< QString, QString > contexts;
101   std::vector< sptr< Dictionary::Class > > activeDicts;
102 
103   std::set< gd::wstring > alts; // Accumulated main forms
104   std::list< sptr< Dictionary::WordSearchRequest > > altSearches;
105   bool altsDone, bodyDone;
106   std::list< sptr< Dictionary::DataRequest > > bodyRequests;
107   bool foundAnyDefinitions;
108   bool closePrevSpan; // Indicates whether the last opened article span is to
109                       // be closed after the article ends.
110   sptr< WordFinder > stemmedWordFinder; // Used when there're no results
111 
112   /// A sequence of words and spacings between them, including the initial
113   /// spacing before the first word and the final spacing after the last word.
114   typedef QList< QString > Words;
115   typedef QList< QString > Spacings;
116 
117   /// Splits the given string into words and spacings between them.
118   QPair< Words, Spacings > splitIntoWords( QString const & );
119 
120   QPair< Words, Spacings > splittedWords;
121   int currentSplittedWordStart;
122   int currentSplittedWordEnd;
123   QString currentSplittedWordCompound;
124   QString lastGoodCompoundResult;
125   bool firstCompoundWasFound;
126   int articleSizeLimit;
127   bool needExpandOptionalParts;
128   bool ignoreDiacritics;
129 
130 public:
131 
132   ArticleRequest( QString const & word, QString const & group,
133                   QMap< QString, QString > const & contexts,
134                   std::vector< sptr< Dictionary::Class > > const & activeDicts,
135                   std::string const & header,
136                   int sizeLimit, bool needExpandOptionalParts_,
137                   bool ignoreDiacritics = false );
138 
139   virtual void cancel();
140 //  { finish(); } // Add our own requests cancellation here
141 
142 private slots:
143 
144   void altSearchFinished();
145   void bodyFinished();
146   void stemmedSearchFinished();
147   void individualWordFinished();
148 
149 private:
150 
151   /// Appends the given string to 'data', with locking its mutex.
152   void appendToData( std::string const & );
153 
154   /// Uses stemmedWordFinder to perform the next step of looking up word
155   /// combinations.
156   void compoundSearchNextStep( bool lastSearchSucceeded );
157 
158   /// Creates a single word out of the [currentSplittedWordStart..End] range.
159   QString makeSplittedWordCompound();
160 
161   /// Makes an html link to the given word.
162   std::string linkWord( QString const & );
163 
164   /// Escapes the spacing between the words to include in html.
165   std::string escapeSpacing( QString const & );
166 
167   /// Find end of corresponding </div> tag
168   int findEndOfCloseDiv( QString const &, int pos );
169 };
170 
171 
172 #endif
173