1 #include <QSettings>
2 #include <QDir>
3 #include <QInputDialog>
4 #include <QMessageBox>
5 #include <QFile>
6 #include <QMenu>
7 #include <QDebug>
8 #include <QTimer>
9 
10 #include "lthemeengine.h"
11 #include "qsseditordialog.h"
12 #include "qsspage.h"
13 #include "ui_qsspage.h"
14 
15 #define QSS_FULL_PATH_ROLE (Qt::ItemDataRole(Qt::UserRole))
16 #define QSS_WRITABLE_ROLE (Qt::ItemDataRole(Qt::UserRole + 1))
17 
QSSPage(QWidget * parent,bool desktop)18 QSSPage::QSSPage(QWidget *parent, bool desktop) : TabPage(parent), m_ui(new Ui::QSSPage){
19   m_ui->setupUi(this);
20   desktop_qss = desktop;
21   QDir("/").mkpath(lthemeengine::userStyleSheetPath());
22   m_menu = new QMenu(this);
23   m_menu->addAction(QIcon::fromTheme("accessories-text-editor"), tr("Edit"), this, SLOT(on_editButton_clicked()));
24   m_menu->addAction(tr("Rename"), this, SLOT(on_renameButton_clicked()));
25   m_menu->addSeparator();
26   m_menu->addAction(QIcon::fromTheme("edit-delete"), tr("Remove"), this, SLOT(on_removeButton_clicked()));
27   readSettings();
28   //icons
29   m_ui->createButton->setIcon(QIcon::fromTheme("document-new"));
30   m_ui->editButton->setIcon(QIcon::fromTheme("accessories-text-editor"));
31   m_ui->removeButton->setIcon(QIcon::fromTheme("edit-delete"));
32   m_ui->tool_enable->setEnabled(false);
33   m_ui->tool_disable->setEnabled(false);
34   m_ui->copyButton->setEnabled(false);
35 }
36 
~QSSPage()37 QSSPage::~QSSPage(){
38   delete m_ui;
39 }
40 
writeSettings()41 void QSSPage::writeSettings(){
42   QStringList styleSheets;
43   QSettings settings(lthemeengine::configFile(), QSettings::IniFormat);
44   for(int i = m_ui->qssListWidget->count()-1; i>=0; i--){
45     QListWidgetItem *item = m_ui->qssListWidget->item(i);
46     styleSheets << item->data(QSS_FULL_PATH_ROLE).toString();
47   }
48   if(desktop_qss){ settings.setValue("Interface/desktop_stylesheets", styleSheets); }
49   else{ settings.setValue("Interface/stylesheets", styleSheets); }
50 }
51 
on_qssListWidget_currentItemChanged(QListWidgetItem * current,QListWidgetItem *)52 void QSSPage::on_qssListWidget_currentItemChanged(QListWidgetItem *current, QListWidgetItem *){
53   if(current!=0){
54     m_ui->list_disabled->clearSelection(); //clear any current selection on the other widget
55     m_ui->list_disabled->setCurrentRow(-1);
56     m_ui->tool_enable->setEnabled(false);
57   }
58   //qDebug() << "Got Current Item Changed";
59   m_ui->tool_disable->setEnabled(current!=0);
60   m_ui->copyButton->setEnabled(current!=0);
61   if(current){
62     m_ui->editButton->setEnabled(current->data(QSS_WRITABLE_ROLE).toBool());
63     m_ui->removeButton->setEnabled(current->data(QSS_WRITABLE_ROLE).toBool());
64     m_ui->renameButton->setEnabled(current->data(QSS_WRITABLE_ROLE).toBool());
65     }
66   else{
67     m_ui->editButton->setEnabled(false);
68     m_ui->removeButton->setEnabled(false);
69     m_ui->renameButton->setEnabled(false);
70     }
71 }
72 
on_list_disabled_currentItemChanged(QListWidgetItem * current,QListWidgetItem *)73 void QSSPage::on_list_disabled_currentItemChanged(QListWidgetItem *current, QListWidgetItem *){
74   if(current!=0){
75     m_ui->qssListWidget->clearSelection(); //clear any current selection on the other widget
76     m_ui->qssListWidget->setCurrentRow(-1);
77     m_ui->tool_disable->setEnabled(false);
78   }
79   //qDebug() << "Got Current Item Changed";
80   m_ui->tool_enable->setEnabled(current!=0);
81   m_ui->copyButton->setEnabled(current!=0);
82   if(current){
83     m_ui->editButton->setEnabled(current->data(QSS_WRITABLE_ROLE).toBool());
84     m_ui->removeButton->setEnabled(current->data(QSS_WRITABLE_ROLE).toBool());
85     m_ui->renameButton->setEnabled(current->data(QSS_WRITABLE_ROLE).toBool());
86     }
87   else{
88     m_ui->editButton->setEnabled(false);
89     m_ui->removeButton->setEnabled(false);
90     m_ui->renameButton->setEnabled(false);
91     }
92 }
93 
on_createButton_clicked()94 void QSSPage::on_createButton_clicked(){
95   QString name = QInputDialog::getText(this, tr("Enter Style Sheet Name"), tr("File name:"));
96   if(name.isEmpty()){ return; }
97   if(!name.endsWith(".qss", Qt::CaseInsensitive)){ name.append(".qss"); }
98   QString filePath;
99     if(desktop_qss){ filePath = lthemeengine::userDesktopStyleSheetPath() + name; }
100     else{ filePath = lthemeengine::userStyleSheetPath() + name; }
101   if(QFile::exists(filePath)){
102     QMessageBox::warning(this, tr("Error"), tr("The file \"%1\" already exists").arg(filePath));
103     return;
104     }
105   // Make sure the directory exists
106   QString dir = filePath.section("/",0,-2);
107   if(!QFile::exists(dir)){
108     QDir D(dir);
109     D.mkpath(dir);
110   }
111   //creating empty file
112   QFile file(filePath);
113   file.open(QIODevice::WriteOnly);
114   file.close();
115   //creating item
116   QFileInfo info(filePath);
117   QListWidgetItem *item = new QListWidgetItem(info.fileName(),  m_ui->list_disabled);
118   item->setToolTip(info.filePath());
119   item->setData(QSS_FULL_PATH_ROLE, info.filePath());
120   item->setData(QSS_WRITABLE_ROLE, info.isWritable());
121   m_ui->list_disabled->setCurrentRow(m_ui->list_disabled->count()-1);
122   QTimer::singleShot(10, this, SLOT(on_editButton_clicked()) );
123 }
124 
on_editButton_clicked()125 void QSSPage::on_editButton_clicked(){
126   QListWidgetItem *item = currentSelection();
127   if(item){
128     QSSEditorDialog dialog(item->data(QSS_FULL_PATH_ROLE).toString(), this);
129     dialog.exec();
130     }
131 }
132 
on_copyButton_clicked()133 void QSSPage::on_copyButton_clicked(){
134  QListWidgetItem *sel = currentSelection();
135   if(sel==0){ return; }
136  QString name = QInputDialog::getText(this, tr("Enter Style Sheet Name"), tr("File name:"), QLineEdit::Normal, sel->text().section(".qss",0,0)+"_copy");
137   if(name.isEmpty()){ return; }
138   if(!name.endsWith(".qss", Qt::CaseInsensitive)){ name.append(".qss"); }
139   QString filePath;
140     if(desktop_qss){ filePath = lthemeengine::userDesktopStyleSheetPath() + name; }
141     else{ filePath = lthemeengine::userStyleSheetPath() + name; }
142   if(QFile::exists(filePath)){
143     QMessageBox::warning(this, tr("Error"), tr("The file \"%1\" already exists").arg(filePath));
144     return;
145     }
146   // Make sure the directory exists
147   QString dir = filePath.section("/",0,-2);
148   if(!QFile::exists(dir)){
149     QDir D(dir);
150     D.mkpath(dir);
151   }
152   //Copy the file over
153   QFile::copy(sel->data(QSS_FULL_PATH_ROLE).toString(), filePath);
154   //creating item
155   QFileInfo info(filePath);
156   QListWidgetItem *item = new QListWidgetItem(info.fileName(),  m_ui->list_disabled);
157   item->setToolTip(info.filePath());
158   item->setData(QSS_FULL_PATH_ROLE, info.filePath());
159   item->setData(QSS_WRITABLE_ROLE, info.isWritable());
160   m_ui->list_disabled->setCurrentRow(m_ui->list_disabled->count()-1);
161 }
162 
on_removeButton_clicked()163 void QSSPage::on_removeButton_clicked(){
164   QListWidgetItem *item = currentSelection();
165   if(!item){ return; }
166   int button = QMessageBox::question(this, tr("Confirm Remove"),tr("Are you sure you want to remove style sheet \"%1\"?").arg(item->text()), QMessageBox::Yes | QMessageBox::No);
167   if(button == QMessageBox::Yes){ QFile::remove(item->data(QSS_FULL_PATH_ROLE).toString()); }
168   delete item;
169 }
170 
on_tool_enable_clicked()171 void QSSPage::on_tool_enable_clicked(){
172   QList<QListWidgetItem*> sel = m_ui->list_disabled->selectedItems();
173   //qDebug() << "Got Selection:" << sel.count();
174   for(int i=0; i<sel.length(); i++){
175     m_ui->qssListWidget->addItem(sel[i]->clone());
176     delete sel[i];
177     //QCoreApplication::processEvents();
178     m_ui->qssListWidget->setCurrentRow(m_ui->qssListWidget->count()-1);
179   }
180 
181 }
182 
on_tool_disable_clicked()183 void QSSPage::on_tool_disable_clicked(){
184   QList<QListWidgetItem*> sel = m_ui->qssListWidget->selectedItems();
185   //qDebug() << "Got Selection:" << sel.count();
186   for(int i=0; i<sel.length(); i++){
187     m_ui->list_disabled->addItem(sel[i]->clone());
188     delete sel[i];
189     //QCoreApplication::processEvents();
190     m_ui->list_disabled->setCurrentRow(m_ui->list_disabled->count()-1);
191   }
192 }
193 
on_tool_priority_up_clicked()194 void QSSPage::on_tool_priority_up_clicked(){
195   QList<QListWidgetItem*> sel = m_ui->qssListWidget->selectedItems();
196   for(int i=0; i<sel.length(); i++){
197     int index = m_ui->qssListWidget->row(sel[i]);
198     //qDebug() << "Move Item Up:" << index;
199     if(index>0){
200       m_ui->qssListWidget->insertItem(index-1, m_ui->qssListWidget->takeItem(index));
201       m_ui->qssListWidget->setCurrentRow(index-1);
202     }
203   }
204 }
205 
on_tool_priority_down_clicked()206 void QSSPage::on_tool_priority_down_clicked(){
207   QList<QListWidgetItem*> sel = m_ui->qssListWidget->selectedItems();
208   for(int i=0; i<sel.length(); i++){
209     int index = m_ui->qssListWidget->row(sel[i]);
210     //qDebug() << "Move Item Down:" << index;
211     if(index<(m_ui->qssListWidget->count()-1) ){
212       m_ui->qssListWidget->insertItem(index+1, m_ui->qssListWidget->takeItem(index));
213       m_ui->qssListWidget->setCurrentRow(index+1);
214     }
215   }
216 }
217 
readSettings()218 void QSSPage::readSettings(){
219   //load stylesheets
220   m_ui->qssListWidget->clear();
221   m_ui->list_disabled->clear();
222   //Read the currently-enabled settings
223   QSettings settings(lthemeengine::configFile(), QSettings::IniFormat);
224   QStringList styleSheets;
225   if(desktop_qss){ styleSheets = settings.value("Interface/desktop_stylesheets").toStringList(); }
226   else{ styleSheets = settings.value("Interface/stylesheets").toStringList(); }
227   for(int i=0; i<styleSheets.length(); i++){
228     if(styleSheets[i].contains("..") || styleSheets[i].contains("//") ){
229       //Get the absolute path for matching later
230       styleSheets[i] = QFileInfo(styleSheets[i]).absoluteFilePath();
231     }
232   }
233   //Now load the items into list widgets
234   //qDebug() << "Found Stylesheets" << styleSheets;
235   if(desktop_qss){ findStyleSheets(QStringList() << lthemeengine::userDesktopStyleSheetPath() << lthemeengine::sharedDesktopStyleSheetPath(), styleSheets); }
236   else{findStyleSheets(QStringList() << lthemeengine::userStyleSheetPath() << lthemeengine::sharedStyleSheetPath(), styleSheets); }
237 
238 }
239 
findStyleSheets(QStringList paths,QStringList enabled)240 void QSSPage::findStyleSheets(QStringList paths, QStringList enabled){
241   paths.removeDuplicates();
242   std::reverse(enabled.begin(), enabled.end()); // reverse for proper order
243   QMap<int, QString> sortedStylesSheets;
244   for(int i=0; i<paths.length(); i++){
245     if(!QFile::exists(paths[i])){ continue; }
246     QDir dir(paths[i]);
247     dir.setFilter(QDir::Files);
248     dir.setNameFilters(QStringList() << "*.qss");
249     foreach (QFileInfo info, dir.entryInfoList()){
250       if(enabled.contains(info.filePath())){ sortedStylesSheets[enabled.indexOf(info.filePath())] = info.filePath(); }
251       else{
252         QListWidgetItem *item = new QListWidgetItem(info.fileName());
253         item->setToolTip(info.filePath());
254         item->setData(QSS_FULL_PATH_ROLE, info.filePath());
255         item->setData(QSS_WRITABLE_ROLE, info.isWritable());
256         m_ui->list_disabled->addItem(item);
257       }
258     }
259   }
260   QMapIterator<int, QString> i(sortedStylesSheets);
261   while (i.hasNext()) {
262     i.next();
263     QFileInfo info(i.value());
264     if (info.isFile()) {
265       QListWidgetItem *item = new QListWidgetItem(info.fileName());
266       item->setToolTip(info.filePath());
267       item->setData(QSS_FULL_PATH_ROLE, info.filePath());
268       item->setData(QSS_WRITABLE_ROLE, info.isWritable());
269       m_ui->qssListWidget->addItem(item);
270     }
271   }
272   m_ui->list_disabled->sortItems(Qt::AscendingOrder);
273 
274 }
275 
on_renameButton_clicked()276 void QSSPage::on_renameButton_clicked(){
277   QListWidgetItem *item = currentSelection();
278   if(!item){ return; }
279   QString name = QInputDialog::getText(this, tr("Rename Style Sheet"), tr("Style sheet name:"), QLineEdit::Normal, item->text(), 0);
280   if(name.isEmpty()){ return; }
281   if(!m_ui->qssListWidget->findItems(name, Qt::MatchExactly).isEmpty() || !m_ui->list_disabled->findItems(name, Qt::MatchExactly).isEmpty()){
282     QMessageBox::warning(this, tr("Error"), tr("The style sheet \"%1\" already exists").arg(name));
283     return;
284     }
285   if(!name.endsWith(".qss", Qt::CaseInsensitive)){ name.append(".qss"); }
286   QString newPath = lthemeengine::userStyleSheetPath() + name;
287   if(!QFile::rename(item->data(QSS_FULL_PATH_ROLE).toString(), newPath)){
288     QMessageBox::warning(this, tr("Error"), tr("Unable to rename file"));
289     return;
290     }
291   item->setText(name);
292   item->setData(QSS_FULL_PATH_ROLE, newPath);
293   item->setToolTip(newPath);
294 }
295 
on_qssListWidget_customContextMenuRequested(const QPoint & pos)296 void QSSPage::on_qssListWidget_customContextMenuRequested(const QPoint &pos){
297   QListWidgetItem *item = m_ui->qssListWidget->currentItem();
298   if(item && item->data(QSS_WRITABLE_ROLE).toBool()){ m_menu->exec(m_ui->qssListWidget->viewport()->mapToGlobal(pos)); }
299 }
300 
currentSelection()301 QListWidgetItem* QSSPage::currentSelection(){
302   QListWidgetItem *item = m_ui->qssListWidget->currentItem();
303   if(item==0){ item = m_ui->list_disabled->currentItem(); }
304   return item;
305 }
306