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