1 /*
2  * Copyright (C) 2013-2018 Daniel Nicoletti <dantti12@gmail.com>
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2.1 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
17  */
18 #ifndef CUTELEE_VIEW_H
19 #define CUTELEE_VIEW_H
20 
21 #include <QObject>
22 #include <QStringList>
23 #include <QLocale>
24 #include <QVector>
25 
26 #include <Cutelyst/View>
27 
28 class QTranslator;
29 
30 namespace Cutelee {
31 class Engine;
32 }
33 
34 namespace Cutelyst {
35 
36 class CuteleeViewPrivate;
37 /**
38  * CuteleeView is a Cutelyst::View handler that renders templates
39  * using Cutelee engine.
40  *
41  * This View also exports a Cutelee tag for dealing with
42  * Cutelyst::Context::uriFor():
43  *
44  * {% c_uri_for "/path" "arg1" "arg2" QUERY "foo=bar" c.req.queryParams %}
45  *
46  * Where only the path is required, and QUERY keyword must preceed query parameters
47  */
48 class CUTELYST_VIEW_CUTELEE_EXPORT CuteleeView final : public View
49 {
50     Q_OBJECT
51     Q_DECLARE_PRIVATE(CuteleeView)
52 public:
53     /*!
54      * Constructs a CuteleeView object with the given parent and name.
55      */
56     explicit CuteleeView(QObject *parent = nullptr, const QString &name = QString());
57 
58     Q_PROPERTY(QStringList includePaths READ includePaths WRITE setIncludePaths NOTIFY changed)
59     /*!
60      * Returns the list of include paths
61      */
62     QStringList includePaths() const;
63 
64     /*!
65      * Sets the list of include paths which will be looked for when resolving templates files
66      */
67     void setIncludePaths(const QStringList &paths);
68 
69     Q_PROPERTY(QString templateExtension READ templateExtension WRITE setTemplateExtension NOTIFY changed)
70     /*!
71      * Returns the template extension
72      */
73     QString templateExtension() const;
74 
75     /*!
76      * Sets the template extension, defaults to ".html"
77      */
78     void setTemplateExtension(const QString &extension);
79 
80     Q_PROPERTY(QString wrapper READ wrapper WRITE setWrapper NOTIFY changed)
81 
82     /*!
83      * Returns the template wrapper.
84      */
85     QString wrapper() const;
86 
87     /*!
88      * Sets the template wrapper name, the template will be rendered into
89      * content variable in which the wrapper template should render.
90      */
91     void setWrapper(const QString &name);
92 
93     Q_PROPERTY(bool cache READ isCaching WRITE setCache NOTIFY changed)
94     /*!
95      * Returns true if caching is enabled
96      */
97     bool isCaching() const;
98 
99     /*!
100      * Sets if template caching should be done, this increases
101      * performance at the cost of higher memory usage.
102      */
103     void setCache(bool enable);
104 
105     /**
106      * Returns the Cutelee::Engine pointer that is used by this engine.
107      */
108     Cutelee::Engine *engine() const;
109 
110     /**
111      * When called cache is set to true and templates are loaded.
112      */
113     void preloadTemplates();
114 
115     QByteArray render(Context *c) const final;
116 
117     /**
118      * Adds a \a translator for the specified \a locale to the list of translators.
119      *
120      * \par Example usage
121      * \code{.cpp}
122      * bool MyCutelystApp::init()
123      * {
124      *      // ...
125      *
126      *      auto view = new CuteleeView(this);
127      *
128      *      auto deDeTrans = new QTranslator(this);
129      *      if (deDeTrans->load(QStringLiteral("de_DE"), QStringLiteral("/path/to/my/translations")) {
130      *          view->addTranslator(QLocale("de_DE"), deDeTrans);
131      *      }
132      *
133      *      auto ptBrTrans = new QTranslator(this);
134      *      if (ptBrTrans->load(QStringLiteral("pt_BR"), QStringLiteral("/path/to/my/translations")) {
135      *          view->addTranslator(QLocale("pt_BR"), ptBrTrans);
136      *      }
137      *
138      *      // ...
139      * }
140      * \endcode
141      *
142      * \sa loadTranslationsFromDir()
143      *
144      * \since Cutelyst 1.5.0
145      */
146     void addTranslator(const QLocale &locale, QTranslator *translator);
147 
148     /**
149      * Adds a \a translator for the specified \a locale to the list of translators.
150      *
151      * The \a locale string should be parseable by QLocale.
152      *
153      * \overload
154      *
155      * \sa loadTranslationsFromDir()
156      *
157      * \since Cutelyst 1.4.0
158      */
159     void addTranslator(const QString &locale, QTranslator *translator);
160 
161     /**
162      * Dynamically adds translation \a catalog at \a path to the translator.
163      *
164      * Translation catalogs can be used to dynamically integrate translations into the
165      * CuteleeView, for example for plugins and themes. The \a catalog could be the name
166      * of an extension for example that is loaded from a locale specifc directory under \a path.
167      *
168      * The catalog will be loaded in the following way: /path/locale/catalog, for example
169      * \c /usr/share/mycutelystapp/l10n/de_DE/fancytheme.qm. The current locale is defined by
170      * Context::locale() when rendering the theme. The \a path \c /usr/share/myapp/l10n would
171      * then contain locale specific subdirectories like de_DE, pt_BR, etc. that contain the
172      * translation files named by \a catalog.
173      *
174      * \par Usage example:
175      * \code{.cpp}
176      * bool MyCutelystApp::init()
177      * {
178      *      // ...
179      *
180      *      auto view = new CuteleeView(this);
181      *      view->addTranslationCatalog(QStringLiteral("/usr/share/mycutelystapp/l10n"), QStringLiteral("fancytheme"));
182      *
183      *      // ...
184      * }
185      * \endcode
186      *
187      * \since Cutelyst 1.5.0
188      */
189     void addTranslationCatalog(const QString &path, const QString &catalog);
190 
191     /**
192      * Adds a dictionary of translation catalogs and paths to the translator.
193      *
194      * The \a key of the QHash is the name of the catalog, the \a value is the path.
195      * See addTranslationCatalog() for more information about translation catalogs.
196      *
197      * \since Cutelyst 1.5.0
198      */
199     void addTranslationCatalogs(const QMultiHash<QString, QString> &catalogs);
200 
201     /**
202      * Loads translations for a specific @p filename from a single directory and returns a list of added locales.
203      *
204      * This can be used to load translations for a template if the translation file names follow a common schema.
205      * Let us assume you organised your translation files as follows:
206      * @li @c /usr/share/myapp/translations/mytemplate_de.qm
207      * @li @c /usr/share/myapp/translations/mytemplate_pt_BR.qm
208      * @li @c ...
209      *
210      * You can then use loadTranslationsFromDir() on your registered CuteleeView object as follows:
211      * @code{.cpp}
212      * bool MyApp::init()
213      * {
214      *      auto view = new CuteleeView(this);
215      *      view->loadTranslationsFromDir(QStringLiteral("mytemplate"), QStringLiteral("/usr/share/myapp/translations"), QStringLiteral("_"));
216      * }
217      * @endcode
218      *
219      * @p prefix is the part between the file name and the locale part. In the example above it is @c "_", if it is not set the default @c "." will be used. The
220      * @p suffix is the file name suffix that defaults to <code>".qm"</code>.
221      *
222      * @sa addTranslator(), loadTranslationsFromDir()
223      *
224      * @since Cuteylst 2.1.0
225      */
226     QVector<QLocale> loadTranslationsFromDir(const QString &filename, const QString &directory, const QString &prefix = QStringLiteral("."), const QString &suffix = QStringLiteral(".qm"));
227 
228 Q_SIGNALS:
229     void changed();
230 };
231 
232 }
233 
234 #endif // CUTELEE_VIEW_H
235