]> git.lyx.org Git - lyx.git/blob - src/frontends/qt4/GuiLyXFiles.cpp
Fix strings
[lyx.git] / src / frontends / qt4 / GuiLyXFiles.cpp
1 /**
2  * \file GuiLyXFiles.cpp
3  * This file is part of LyX, the document processor.
4  * Licence details can be found in the file COPYING.
5  *
6  * \author Jürgen Spitzmüller
7  *
8  * Full author contact details are available in file CREDITS.
9  */
10
11 #include <config.h>
12
13 #include "GuiLyXFiles.h"
14 #include "GuiApplication.h"
15 #include "qt_helpers.h"
16
17 #include "FileDialog.h"
18 #include "Buffer.h"
19 #include "BufferParams.h"
20 #include "FuncRequest.h"
21 #include "Language.h"
22 #include "LyXRC.h"
23
24 #include "support/environment.h"
25 #include "support/filetools.h"
26 #include "support/gettext.h"
27 #include "support/lstrings.h"
28 #include "support/Messages.h"
29 #include "support/qstring_helpers.h"
30 #include "support/Package.h"
31
32 #include <QDirIterator>
33 #include <QFileIconProvider>
34 #include <QTreeWidget>
35
36 using namespace std;
37 using namespace lyx::support;
38
39 namespace lyx {
40 namespace frontend {
41
42 namespace {
43
44 void getFiles(QMap<QString, QString> & in, QString const type)
45 {
46         // We look for lyx files in the subdirectory dir of
47         //   1) user_lyxdir
48         //   2) build_lyxdir (if not empty)
49         //   3) system_lyxdir
50         // in this order. Files with a given sub-hierarchy will
51         // only be listed once.
52         // We also consider i18n subdirectories and prefer them.
53         QStringList dirs;
54         QStringList relpaths;
55         QStringList langcodes;
56
57         // The three locations to look at.
58         string const user = addPath(package().user_support().absFileName(), fromqstr(type));
59         string const build = addPath(package().build_support().absFileName(), fromqstr(type));
60         string const system = addPath(package().system_support().absFileName(), fromqstr(type));
61
62         // If the LANGUAGE variable is set, use it as a fallback for searching for files.
63         string lang = getGuiMessages().language();
64         string const language = getEnv("LANGUAGE");
65         if (!language.empty())
66                 lang += ":" + language;
67
68         // Get all supported languages (by code) in order to exclude those
69         // dirs later.
70         QAbstractItemModel * language_model = guiApp->languageModel();
71         for (int i = 0; i != language_model->rowCount(); ++i) {
72                 QModelIndex index = language_model->index(i, 0);
73                 Language const * lang =
74                         languages.getLanguage(fromqstr(index.data(Qt::UserRole).toString()));
75                 if (!lang)
76                         continue;
77                 string const code = lang->code();
78                 langcodes << toqstr(code);
79                 // Also store code without country code
80                 string const shortcode = token(code, '_', 0);
81                 if (shortcode != code)
82                         langcodes << toqstr(shortcode);
83         }
84
85         for (auto const & l : getVectorFromString(lang, ":")) {
86                 FileName tmp;
87                 // First try with the full name
88                 // `en' files are not in a subdirectory
89                 if (l == "en")
90                         break;
91                 else {
92                         dirs << toqstr(addPath(user, l));
93                         dirs << toqstr(addPath(build, l));
94                         dirs << toqstr(addPath(system, l));
95                 }
96                 // Then the name without country code
97                 string const shortl = token(l, '_', 0);
98                 if (shortl != l) {
99                         dirs << toqstr(addPath(user, shortl));
100                         dirs << toqstr(addPath(build, shortl));
101                         dirs << toqstr(addPath(system, shortl));
102                 }
103         }
104
105         // Next, search in the base path
106         dirs << toqstr(user)
107              << toqstr(build)
108              << toqstr(system);
109
110         for (int i = 0; i < dirs.size(); ++i) {
111                 QString const dir = dirs.at(i);
112                 QDirIterator it(dir, QDir::Files, QDirIterator::Subdirectories);
113                 while (it.hasNext()) {
114                         QString fn(QFile(it.next()).fileName());
115                         if (!fn.endsWith(".lyx"))
116                                 continue;
117                         QString const relpath = toqstr(makeRelPath(qstring_to_ucs4(fn),
118                                                                    qstring_to_ucs4(dir)));
119                         // <cat>/
120                         int s = relpath.indexOf('/', 0);
121                         QString cat = qt_("General");
122                         if (s != -1) {
123                                 // <cat>/<subcat>/
124                                 cat = relpath.left(s);
125                                 int sc = relpath.indexOf('/', s + 1);
126                                 QString const subcat = (sc == -1) ?
127                                                         QString() : relpath.mid(s + 1, sc - s - 1);
128                                 if (langcodes.contains(cat)
129                                     && !langcodes.contains(dir.right(dir.lastIndexOf('/'))))
130                                         // Skip i18n dir
131                                         continue;
132                                 if (!subcat.isEmpty())
133                                         cat += '/' + subcat;
134                         }
135                         if (!relpaths.contains(relpath)) {
136                                 relpaths.append(relpath);
137                                 in.insert(fn, cat);
138                         }
139                 }
140         }
141 }
142
143 }// namespace anon
144
145
146 GuiLyXFiles::GuiLyXFiles(GuiView & lv)
147         : GuiDialog(lv, "lyxfiles", qt_("New File From Template"))
148 {
149         setupUi(this);
150
151         // The filter bar
152         filter_ = new FancyLineEdit(this);
153         filter_->setButtonPixmap(FancyLineEdit::Right, getPixmap("images/", "editclear", "svgz,png"));
154         filter_->setButtonVisible(FancyLineEdit::Right, true);
155         filter_->setButtonToolTip(FancyLineEdit::Right, qt_("Clear text"));
156         filter_->setAutoHideButton(FancyLineEdit::Right, true);
157         filter_->setPlaceholderText(qt_("All available files"));
158         filter_->setToolTip(qt_("Enter string to filter the list of available files"));
159 #if (QT_VERSION < 0x050000)
160         connect(filter_, SIGNAL(downPressed()),
161                 filesLW, SLOT(setFocus()));
162 #else
163         connect(filter_, &FancyLineEdit::downPressed,
164                 filesLW, [=](){ focusAndHighlight(filesLW); });
165 #endif
166
167         filterBarL->addWidget(filter_, 0);
168         findKeysLA->setBuddy(filter_);
169
170         connect(buttonBox, SIGNAL(clicked(QAbstractButton *)),
171                 this, SLOT(slotButtonBox(QAbstractButton *)));
172
173         connect(filesLW, SIGNAL(itemClicked(QTreeWidgetItem *, int)),
174                 this, SLOT(changed_adaptor()));
175         connect(filesLW, SIGNAL(itemSelectionChanged()),
176                 this, SLOT(changed_adaptor()));
177         connect(filter_, SIGNAL(textEdited(QString)),
178                 this, SLOT(filterLabels()));
179         connect(filter_, SIGNAL(rightButtonClicked()),
180                 this, SLOT(resetFilter()));
181
182         bc().setPolicy(ButtonPolicy::OkApplyCancelPolicy);
183         bc().setOK(buttonBox->button(QDialogButtonBox::Open));
184         bc().setCancel(buttonBox->button(QDialogButtonBox::Cancel));
185
186         //filesLW->setViewMode(QListView::ListMode);
187         filesLW->setIconSize(QSize(22, 22));
188
189         fileTypeCO->addItem(qt_("Templates"), toqstr("templates"));
190         fileTypeCO->addItem(qt_("Examples"), toqstr("examples"));
191
192         setFocusProxy(filter_);
193 }
194
195
196 void GuiLyXFiles::changed_adaptor()
197 {
198         changed();
199 }
200
201
202 void GuiLyXFiles::on_fileTypeCO_activated(int)
203 {
204         updateContents();
205 }
206
207
208 void GuiLyXFiles::on_filesLW_itemDoubleClicked(QTreeWidgetItem *, int)
209 {
210         applyView();
211         dispatchParams();
212         close();
213 }
214
215
216 void GuiLyXFiles::on_browsePB_pressed()
217 {
218         bool const examples = (type_ == "examples");
219         FileDialog dlg(qt_("Select template file"));
220         dlg.setButton1(qt_("D&ocuments"), toqstr(lyxrc.document_path));
221         if (examples)
222                 dlg.setButton2(qt_("&Examples"), toqstr(lyxrc.example_path));
223         else
224                 dlg.setButton2(qt_("&Templates"), toqstr(lyxrc.template_path));
225
226         FileDialog::Result result = dlg.open(examples ? toqstr(lyxrc.example_path)
227                                                       : toqstr(lyxrc.template_path),
228                                  QStringList(qt_("LyX Documents (*.lyx)")));
229
230         if (result.first != FileDialog::Later && !result.second.isEmpty()) {
231                 file_ = toqstr(FileName(fromqstr(result.second)).absFileName());
232                 dispatchParams();
233                 close();
234         }
235 }
236
237
238 void GuiLyXFiles::updateContents()
239 {
240         QString type = fileTypeCO->itemData(fileTypeCO->currentIndex()).toString();
241         QMap<QString, QString> files;
242         getFiles(files, type);
243
244         filesLW->clear();
245         QFileIconProvider iconprovider;
246         QStringList cats;
247         QMap<QString, QString>::const_iterator it = files.constBegin();
248         QFont capfont;
249         capfont.setBold(true);
250         while (it != files.constEnd()) {
251                 QFileInfo const info = QFileInfo(it.key());
252                 QString cat = it.value();
253                 QString subcat;
254                 QString catsave;
255                 if (cat.contains('/')) {
256                         catsave = cat;
257                         cat = catsave.left(catsave.indexOf('/'));
258                         subcat = toqstr(translateIfPossible(
259                                         qstring_to_ucs4(catsave.mid(
260                                                 catsave.indexOf('/') + 1).replace('_', ' '))));
261                 }
262                 cat =  toqstr(translateIfPossible(qstring_to_ucs4(cat.replace('_', ' '))));
263                 QTreeWidgetItem * catItem = new QTreeWidgetItem();
264                 if (!cats.contains(cat)) {
265                         catItem->setText(0, cat);
266                         catItem->setFont(0, capfont);
267                         filesLW->insertTopLevelItem(0, catItem);
268                         catItem->setExpanded(true);
269                         cats << cat;
270                 } else
271                         catItem = filesLW->findItems(cat, Qt::MatchExactly).first();
272                 QTreeWidgetItem * item = new QTreeWidgetItem();
273                 QString const filename = info.fileName();
274                 QString const guiname =
275                                 toqstr(translateIfPossible(
276                                                qstring_to_ucs4(filename.left(filename.lastIndexOf(".lyx")).replace('_', ' '))));
277                 item->setIcon(0, iconprovider.icon(info));
278                 item->setData(0, Qt::UserRole, info.filePath());
279                 item->setData(0, Qt::DisplayRole, guiname);
280                 item->setData(0, Qt::ToolTipRole, info.filePath());
281                 if (subcat.isEmpty())
282                         catItem->addChild(item);
283                 else {
284                         QTreeWidgetItem * subcatItem = new QTreeWidgetItem();
285                         if (cats.contains(catsave)) {
286                                 QList<QTreeWidgetItem *> pcats = filesLW->findItems(cat, Qt::MatchExactly);
287                                 for (int iit = 0; iit < pcats.size(); ++iit) {
288                                         for (int cit = 0; cit < pcats.at(iit)->childCount(); ++cit) {
289                                                 if (pcats.at(iit)->child(cit)->text(0) == subcat) {
290                                                         subcatItem = pcats.at(iit)->child(cit);
291                                                         break;
292                                                 }
293                                         }
294                                 }
295                         } else {
296                                 subcatItem->setText(0, subcat);
297                                 cats << catsave;
298                         }
299                         subcatItem->addChild(item);
300                         catItem->addChild(subcatItem);
301                 }
302                 ++it;
303         }
304         filesLW->sortItems(0, Qt::AscendingOrder);
305         // redo filter
306         filterLabels();
307 }
308
309
310 void GuiLyXFiles::slotButtonBox(QAbstractButton * button)
311 {
312         switch (buttonBox->standardButton(button)) {
313         case QDialogButtonBox::Open:
314                 slotOK();
315                 break;
316         case QDialogButtonBox::Cancel:
317                 slotClose();
318                 break;
319         default:
320                 break;
321         }
322 }
323
324
325 void GuiLyXFiles::filterLabels()
326 {
327         Qt::CaseSensitivity cs = csFindCB->isChecked() ?
328                 Qt::CaseSensitive : Qt::CaseInsensitive;
329         QTreeWidgetItemIterator it(filesLW);
330         while (*it) {
331                 (*it)->setHidden(
332                         (*it)->childCount() == 0
333                         && !(*it)->text(0).contains(filter_->text(), cs)
334                 );
335                 ++it;
336         }
337 }
338
339
340 void GuiLyXFiles::resetFilter()
341 {
342         filter_->setText(QString());
343         filterLabels();
344 }
345
346
347 void GuiLyXFiles::applyView()
348 {
349         file_ = filesLW->currentItem()->data(0, Qt::UserRole).toString();
350 }
351
352
353 bool GuiLyXFiles::isValid()
354 {
355         return filesLW->currentItem() && filesLW->currentItem()->isSelected();
356 }
357
358
359 bool GuiLyXFiles::initialiseParams(string const & type)
360 {
361         type_ = type.empty() ? toqstr("templates") : toqstr(type);
362         paramsToDialog(type_);
363         return true;
364 }
365
366
367 void GuiLyXFiles::paramsToDialog(QString const & command)
368 {
369         if (!command.isEmpty()) {
370                 int i = fileTypeCO->findData(command);
371                 if (i != -1)
372                         fileTypeCO->setCurrentIndex(i);
373         }
374         if (command == "examples")
375                 setTitle(qt_("Open Example File"));
376         else {
377                 setTitle(qt_("New File From Template"));
378         }
379
380         bc().setValid(isValid());
381 }
382
383
384 void GuiLyXFiles::dispatchParams()
385 {
386         if (file_.isEmpty())
387                 return;
388
389         string arg;
390         if (type_ == "templates")
391                 arg = "newfile ";
392         arg += fromqstr(file_);
393         FuncCode const lfun = (type_ == toqstr("examples")) ?
394                 LFUN_FILE_OPEN : getLfun();
395
396         dispatch(FuncRequest(lfun, arg));
397 }
398
399 Dialog * createGuiLyXFiles(GuiView & lv) { return new GuiLyXFiles(lv); }
400
401
402 } // namespace frontend
403 } // namespace lyx
404
405 #include "moc_GuiLyXFiles.cpp"