Medical Imaging Interaction Toolkit  2018.4.99-3e3f1a6e
Medical Imaging Interaction Toolkit
berryQtStyleManager.cpp
Go to the documentation of this file.
1 /*============================================================================
2 
3 The Medical Imaging Interaction Toolkit (MITK)
4 
5 Copyright (c) German Cancer Research Center (DKFZ)
6 All rights reserved.
7 
8 Use of this source code is governed by a 3-clause BSD license that can be
9 found in the LICENSE file.
10 
11 ============================================================================*/
12 
13 #include "berryQtStyleManager.h"
14 
15 #include <QApplication>
16 #include <QFile>
17 #include <QTextStream>
18 #include <QFileInfo>
19 #include <QRegularExpression>
20 #include <QStringList>
21 #include <QDirIterator>
22 #include <QFont>
23 #include <QFontDatabase>
24 #include <QIcon>
25 
26 #include <berryLog.h>
27 #include <berryPlatform.h>
28 #include <berryPlatformUI.h>
30 #include <berryIPreferences.h>
31 
32 #include "berryQtPreferences.h"
33 #include "berryWorkbenchPlugin.h"
34 
35 namespace berry
36 {
37 
38 static QString ParseColor(const QString &subject, const QString &pattern, const QString &fallback)
39 {
40  QRegularExpression re(pattern, QRegularExpression::CaseInsensitiveOption);
41  auto match = re.match(subject);
42 
43  return match.hasMatch()
44  ? match.captured(1)
45  : fallback;
46 }
47 
48 QIcon QtStyleManager::ThemeIcon(const QByteArray &originalSVG)
49 {
50  auto styleSheet = qApp->styleSheet();
51 
52  if (styleSheet.isEmpty())
53  return QPixmap::fromImage(QImage::fromData(originalSVG));
54 
55  auto iconColor = ParseColor(styleSheet,
56  QStringLiteral("iconColor\\s*[=:]\\s*(#[0-9a-f]{6})"),
57  QStringLiteral("#000000"));
58 
59  auto iconAccentColor = ParseColor(styleSheet,
60  QStringLiteral("iconAccentColor\\s*[=:]\\s*(#[0-9a-f]{6})"),
61  QStringLiteral("#ffffff"));
62 
63  auto themedSVG = QString(originalSVG).replace(QStringLiteral("#00ff00"), iconColor, Qt::CaseInsensitive);
64  themedSVG = themedSVG.replace(QStringLiteral("#ff00ff"), iconAccentColor, Qt::CaseInsensitive);
65 
66  return QPixmap::fromImage(QImage::fromData(themedSVG.toLatin1()));
67 }
68 
69 QIcon QtStyleManager::ThemeIcon(const QString &resourcePath)
70 {
71  QFile resourceFile(resourcePath);
72 
73  if (resourceFile.open(QIODevice::ReadOnly))
74  {
75  auto originalSVG = resourceFile.readAll();
76  return ThemeIcon(originalSVG);
77  }
78 
79  BERRY_WARN << "Could not read " << resourcePath;
80  return QIcon();
81 }
82 
84 {
85  AddDefaultStyle();
86  AddDefaultFonts();
87  ReadPreferences();
88 }
89 
90 void QtStyleManager::ReadPreferences()
91 {
94 
95  QString paths = stylePref->Get(QtPreferences::QT_STYLE_SEARCHPATHS, "");
96  QStringList pathList = paths.split(";", QString::SkipEmptyParts);
97  QStringListIterator it(pathList);
98  while (it.hasNext())
99  {
100  AddStyles(it.next());
101  }
102 
103  QString styleName = stylePref->Get(QtPreferences::QT_STYLE_NAME, "");
104  // if a style is contributed via the Qt resource mechanism, it may not be
105  // registered yet.
106  if (Contains(styleName))
107  // do not update the style in the QApplication instance,
108  // since it might not be created yet
109  SetStyle(styleName, false);
110  else
111  SetDefaultStyle(false);
112 }
113 
115 {
116  for (FileNameToStyleMap::const_iterator i = styles.begin(); i != styles.end(); ++i)
117  {
118  delete i.value();
119  }
120 }
121 
122 void QtStyleManager::AddDefaultStyle()
123 {
124 #ifndef _APPLE_
125  AddStyle(":/org.blueberry.ui.qt/darkstyle.qss", "Dark");
126  AddStyle(":/org.blueberry.ui.qt/lightstyle.qss", "Light");
127  defaultStyle = styles[":/org.blueberry.ui.qt/darkstyle.qss"];
128 #endif
129 }
130 
131 void QtStyleManager::AddDefaultFonts()
132 {
133  m_customFontNames.append(QString("<<system>>"));
134 
135  m_customFontNames.append(QString("Fira Sans"));
136  QFontDatabase::addApplicationFont(":/org.blueberry.ui.qt/fonts/FiraSans/FiraSans.ttf");
137 
138  m_customFontNames.append(QString("Light Fira Sans"));
139  QFontDatabase::addApplicationFont(":/org.blueberry.ui.qt/fonts/LightFiraSans/LightFiraSans.ttf");
140 
141  m_customFontNames.append(QString("Roboto"));
142  QFontDatabase::addApplicationFont(":/org.blueberry.ui.qt/fonts/Roboto/Roboto.ttf");
143 
144  m_customFontNames.push_back(QString("Open Sans"));
145  QFontDatabase::addApplicationFont(":/org.blueberry.ui.qt/fonts/OpenSans/OpenSans-Regular.ttf");
146 
147  m_customFontNames.push_back(QString("xkcd"));
148  QFontDatabase::addApplicationFont(":/org.blueberry.ui.qt/fonts/xkcd/xkcd.ttf");
149 }
150 
151 void QtStyleManager::ClearStyles()
152 {
153  for (FileNameToStyleMap::iterator i = styles.begin(); i != styles.end(); )
154  {
155  if (!i.value()->fileName.startsWith(':'))
156  {
157  delete i.value();
158  i = styles.erase(i);
159  }
160  else ++i;
161  }
162  SetDefaultStyle();
163 }
164 
166 {
167  return Style(currentStyle->name, currentStyle->fileName);
168 }
169 
171 {
172  return currentStyle->stylesheet;
173 }
174 
176 {
177  return currentStyle->activeTabStylesheet;
178 }
179 
181 {
182  return currentStyle->tabStylesheet;
183 }
184 
185 void QtStyleManager::AddStyle(const QString& styleFileName,
186  const QString& styleName)
187 {
188  auto newStyle = new ExtStyle();
189 
190  if (styleName.isEmpty())
191  {
192  QFileInfo info(styleFileName);
193  newStyle->name = info.completeBaseName();
194  }
195  else
196  {
197  newStyle->name = styleName;
198  }
199 
200  newStyle->fileName = styleFileName;
201 
202  styles.insert(newStyle->fileName, newStyle);
203 }
204 
205 void QtStyleManager::GetFonts(QStringList& fontNames) const
206 {
207  fontNames = m_customFontNames;
208 }
209 
210 QString QtStyleManager::GetFont() const
211 {
212  return m_currentFont;
213 }
214 
215 void QtStyleManager::AddStyles(const QString& path)
216 {
217  QDirIterator dirIt(path);
218  while (dirIt.hasNext())
219  {
220  QString current = dirIt.next();
221  QFileInfo info = dirIt.fileInfo();
222  if (info.isFile() && info.isReadable())
223  {
224  QString fileName = info.fileName();
225  if (fileName.endsWith("-tab.qss") || fileName.endsWith("-activetab.qss"))
226  continue;
227 
228  if (fileName.endsWith(".qss"))
229  AddStyle(current);
230  }
231  }
232 }
233 
234 void QtStyleManager::ReadStyleData(ExtStyle* style)
235 {
236  QString tabStyleFileName(style->fileName);
237  QString activeTabStyleFileName(style->fileName);
238 
239  int index = style->fileName.lastIndexOf(".qss");
240  tabStyleFileName.replace(index, 4, "-tab.qss");
241  activeTabStyleFileName.replace(index, 4, "-activetab.qss");
242 
243  QFile styleFile(style->fileName);
244  if (styleFile.open(QIODevice::ReadOnly))
245  {
246  QTextStream in(&styleFile);
247  style->stylesheet = in.readAll();
248  }
249  else
250  {
251  BERRY_WARN << "Could not read " << style->fileName.toStdString();
252  }
253 
254  QFile tabStyleFile(tabStyleFileName);
255  if (tabStyleFile.open(QIODevice::ReadOnly))
256  {
257  QTextStream in(&tabStyleFile);
258  style->tabStylesheet = in.readAll();
259  }
260  else
261  {
262  BERRY_WARN << "Could not read " << tabStyleFileName.toStdString();
263  }
264 
265  QFile activeTabStyleFile(activeTabStyleFileName);
266  if (activeTabStyleFile.open(QIODevice::ReadOnly))
267  {
268  QTextStream in(&activeTabStyleFile);
269  style->activeTabStylesheet = in.readAll();
270  }
271  else
272  {
273  BERRY_WARN << "Could not read " << activeTabStyleFileName.toStdString();
274  }
275 }
276 
277 void QtStyleManager::RemoveStyle(const QString& styleFileName)
278 {
279  if (currentStyle->fileName == styleFileName)
280  {
281  SetDefaultStyle();
282  }
283 
284  delete styles.take(styleFileName);
285 }
286 
287 void QtStyleManager::RemoveStyles(const QString& repo)
288 {
289  if (repo.isEmpty())
290  {
291  ClearStyles();
292  return;
293  }
294 
295  for (FileNameToStyleMap::iterator i = styles.begin(); i != styles.end();)
296  {
297  ExtStyle* style = i.value();
298  QFileInfo info(style->fileName);
299  if (info.absolutePath() == repo)
300  {
301  if (style->name == currentStyle->name)
302  {
303  SetDefaultStyle();
304  }
305 
306  i = styles.erase(i);
307  delete style;
308  }
309  else
310  {
311  ++i;
312  }
313  }
314 }
315 
316 void QtStyleManager::GetStyles(StyleList& styleNames) const
317 {
318  for (FileNameToStyleMap::const_iterator i = styles.begin(); i != styles.end(); ++i)
319  styleNames.push_back(Style(i.value()->name, i.value()->fileName));
320 }
321 
322 void QtStyleManager::SetStyle(const QString& fileName)
323 {
324  SetStyle(fileName, true);
325 }
326 
327 void QtStyleManager::SetStyle(const QString& fileName, bool update)
328 {
329  if (fileName.isEmpty())
330  {
331  SetDefaultStyle();
332  return;
333  }
334 
335  FileNameToStyleMap::const_iterator i = styles.find(fileName);
336 
337  ExtStyle* style = nullptr;
338  if (i == styles.end())
339  {
340  BERRY_WARN << "Style " + fileName.toStdString() << " does not exist";
341  style = defaultStyle;
342  }
343  else
344  {
345  style = i.value();
346  }
347  currentStyle = style;
348 
349  ReadStyleData(style);
350 
351  if (update)
352  {
353  qApp->setStyleSheet(currentStyle->stylesheet);
355  }
356 }
357 
358 void QtStyleManager::SetFont(const QString& fontName)
359 {
360  m_currentFont = fontName;
361 }
362 
363 void QtStyleManager::SetFontSize(const int fontSize)
364 {
365  m_currentFontSize = fontSize;
366 }
367 
369 {
370  if( m_currentFont == QString( "<<system>>" ) || m_currentFont == QString( "" ))
371  {
372  qApp->setFont(QFontDatabase::systemFont(QFontDatabase::GeneralFont));
373  }
374  else
375  {
376  QFont font;
377  font.setFamily(m_currentFont);
378  font.setPointSize(m_currentFontSize);
379  qApp->setFont(font);
380  }
381  qApp->setStyleSheet(currentStyle->stylesheet);
383 }
384 
386 {
387  return Style(defaultStyle->name, defaultStyle->fileName);
388 }
389 
391 {
392  SetDefaultStyle(true);
393 }
394 
395 void QtStyleManager::SetDefaultStyle(bool update)
396 {
397  SetStyle(defaultStyle->fileName, update);
398 }
399 
400 bool QtStyleManager::Contains(const QString& fileName) const
401 {
402  return styles.contains(fileName);
403 }
404 
405 }
static const QString QT_STYLE_SEARCHPATHS
QString GetStylesheet() const override
Style GetStyle() const override
void RemoveStyle(const QString &styleFileName) override
void RemoveStyles(const QString &path=QString()) override
static QIcon ThemeIcon(const QByteArray &originalSVG)
void SetFont(const QString &fontName) override
virtual SmartPointer< IPreferences > GetSystemPreferences()=0
static WorkbenchPlugin * GetDefault()
static const QString QT_STYLE_NAME
QString GetActiveTabStylesheet() const override
static void info(const char *fmt,...)
Definition: svm.cpp:86
void GetFonts(QStringList &fontNames) const override
QString GetFont() const override
virtual void UpdateTheme()=0
void SetFontSize(const int fontSize) override
QString GetTabStylesheet() const override
void UpdateWorkbenchFont() override
IPreferencesService * GetPreferencesService() const
static IWorkbench * GetWorkbench()
static const QString QT_STYLES_NODE
static QString ParseColor(const QString &subject, const QString &pattern, const QString &fallback)
void GetStyles(StyleList &styles) const override
#define BERRY_WARN
Definition: berryLog.h:21
static bool in(Reader::Char c, Reader::Char c1, Reader::Char c2, Reader::Char c3, Reader::Char c4)
Definition: jsoncpp.cpp:244
void AddStyles(const QString &path) override
void AddStyle(const QString &styleFileName, const QString &styleName=QString()) override
void SetStyle(const QString &fileName) override
bool Contains(const QString &fileName) const override
Style GetDefaultStyle() const override