1 /*-
2  * Copyright (c) 2016 Marcel Kaiser. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
14  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
15  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
16  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
17  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
18  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
19  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
20  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
21  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
22  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
23  */
24 
25 #include <QVBoxLayout>
26 
27 #include "list.h"
28 #include "desktopfile.h"
29 #include "qt-helper/qt-helper.h"
30 
List(dsbautostart_t * as,QWidget * parent)31 List::List(dsbautostart_t *as, QWidget *parent)
32 	: QWidget(parent) {
33 
34 	list = new ListWidget(parent);
35 	list->setMouseTracking(true);
36 	this->as = as;
37 
38 	QVBoxLayout *vbox = new QVBoxLayout;
39 	vbox->addWidget(list);
40 	setLayout(vbox);
41 	list->setToolTip(QString(tr("Double click to edit.\n" \
42 	    "Use checkbox to activate/deactivate a command.\n" \
43 	    "Use Drag & Drop to add desktop files.")));
44 	if ((ascp = dsbautostart_copy(as)) == NULL) {
45 		if (dsbautostart_error()) {
46 			qh_err(this, EXIT_FAILURE, "%s",
47 			    dsbautostart_strerror());
48 		}
49 	}
50 	for (entry_t *entry = as->entry; entry != NULL; entry = entry->next)
51 		addItem(entry);
52 	_modified = false;
53 	connect(list, SIGNAL(itemChanged(QListWidgetItem *)), this,
54 	    SLOT(catchItemChanged(QListWidgetItem *)));
55 	connect(list, SIGNAL(itemDoubleClicked(QListWidgetItem *)), this,
56 	    SLOT(catchDoubleClicked(QListWidgetItem *)));
57 	connect(list, SIGNAL(itemDroped(QStringList &)), this,
58 	    SLOT(addDesktopFiles(QStringList &)));
59 	connect(list, SIGNAL(deleteKeyPressed()), this, SLOT(delItem()));
60 }
61 
62 bool
modified()63 List::modified()
64 {
65 	return (_modified);
66 }
67 
68 void
unsetModified()69 List::unsetModified()
70 {
71 	dsbautostart_free(ascp);
72 	if ((ascp = dsbautostart_copy(as)) == NULL) {
73 		if (dsbautostart_error()) {
74 			qh_err(this, EXIT_FAILURE, "%s",
75 			    dsbautostart_strerror());
76 		}
77 	}
78 	_modified = false;
79 }
80 
81 void
newItem()82 List::newItem()
83 {
84 	entry_t *entry = dsbautostart_add_entry(as, "", true);
85 
86 	if (entry == NULL)
87 		qh_errx(this, EXIT_FAILURE, "%s", dsbautostart_strerror());
88 	QListWidgetItem *item = List::addItem(entry);
89 	list->editItem(item);
90 	compare();
91 }
92 
93 QListWidgetItem *
addItem(entry_t * entry)94 List::addItem(entry_t *entry)
95 {
96 	QListWidgetItem *item = new QListWidgetItem(entry->cmd);
97 	item->setFlags(Qt::ItemIsEditable | Qt::ItemIsUserCheckable |
98 	    Qt::ItemIsSelectable | Qt::ItemIsEnabled);
99 	item->setCheckState(entry->active ? Qt::Checked : Qt::Unchecked);
100 	item->setData(Qt::UserRole, qVariantFromValue((void *)entry));
101 	list->addItem(item);
102 	items.append(item);
103 
104 	return (item);
105 }
106 
107 void
catchItemChanged(QListWidgetItem * item)108 List::catchItemChanged(QListWidgetItem *item)
109 {
110 	updateItem(item);
111 	compare();
112 }
113 
114 void
catchDoubleClicked(QListWidgetItem * item)115 List::catchDoubleClicked(QListWidgetItem *item)
116 {
117 	list->editItem(item);
118 	list->setCurrentItem(item, QItemSelectionModel::Deselect);
119 }
120 
121 void
delItem()122 List::delItem()
123 {
124 	entry_t *entry;
125 	QListWidgetItem *item = list->currentItem();
126 
127 	if (item == 0)
128 		return;
129 	entry = (entry_t *)item->data(Qt::UserRole).value<void *>();
130 	if (dsbautostart_del_entry(as, entry) == NULL)
131 		qh_errx(this, EXIT_FAILURE, "%s", dsbautostart_strerror());
132 	list->removeItemWidget(item);
133 	items.removeOne(item);
134 	delete item;
135 	compare();
136 }
137 
138 void
moveItemUp()139 List::moveItemUp()
140 {
141 	int row;
142 	entry_t *entry;
143 	QListWidgetItem *item = list->currentItem();
144 
145 	if (item == 0)
146 		return;
147 	entry = (entry_t *)item->data(Qt::UserRole).value<void *>();
148 	if (dsbautostart_entry_move_up(as, entry) == NULL)
149 		qh_errx(this, EXIT_FAILURE, "%s", dsbautostart_strerror());
150 	row = list->currentRow();
151 	if (row == 0)
152 		return;
153 	list->takeItem(row);
154 	list->insertItem(--row, item);
155 	list->setCurrentRow(row);
156 	compare();
157 }
158 
159 void
moveItemDown()160 List::moveItemDown()
161 {
162 	int row;
163 	entry_t *entry;
164 	QListWidgetItem *item = list->currentItem();
165 
166 	if (item == 0)
167 		return;
168 	entry = (entry_t *)item->data(Qt::UserRole).value<void *>();
169 	if (dsbautostart_entry_move_down(as, entry) == NULL)
170 		qh_errx(this, EXIT_FAILURE, "%s", dsbautostart_strerror());
171 	row = list->currentRow();
172 
173 	if (list->count() - 1 == row)
174 		return;
175 	list->takeItem(row);
176 	list->insertItem(++row, item);
177 	list->setCurrentRow(row);
178 	compare();
179 }
180 
181 void
updateItem(QListWidgetItem * item)182 List::updateItem(QListWidgetItem *item)
183 {
184 	bool cbstate = item->checkState() == Qt::Unchecked ? false : true;
185 	entry_t *entry;
186 
187 	entry = (entry_t *)item->data(Qt::UserRole).value<void *>();
188 	if (dsbautostart_set(as, entry, item->text().toUtf8().constData(),
189 	    cbstate) == -1)
190 		qh_errx(this, EXIT_FAILURE, "%s", dsbautostart_strerror());
191 	compare();
192 }
193 
194 void
update()195 List::update()
196 {
197 	for (int i = 0; i < items.size(); i++)
198 		updateItem(items.at(i));
199 }
200 
201 void
undo()202 List::undo()
203 {
204 	dsbautostart_undo(as);
205 	list->clear();
206 	items.clear();
207 	for (entry_t *entry = as->entry; entry != NULL; entry = entry->next)
208 		addItem(entry);
209 	compare();
210 }
211 
212 void
redo()213 List::redo()
214 {
215 	dsbautostart_redo(as);
216 	list->clear();
217 	items.clear();
218 	for (entry_t *entry = as->entry; entry != NULL; entry = entry->next)
219 		addItem(entry);
220 	compare();
221 }
222 
223 bool
canUndo()224 List::canUndo()
225 {
226 	return (dsbautostart_can_undo(as));
227 }
228 
229 bool
canRedo()230 List::canRedo()
231 {
232 
233 	return (dsbautostart_can_redo(as));
234 }
235 
236 void
compare()237 List::compare()
238 {
239 	if (!dsbautostart_cmp(ascp, as)) {
240 		emit listModified(true);
241 		_modified = true;
242 	} else	{
243 		_modified = false;
244 		emit listModified(false);
245 	}
246 }
247 
248 void
addDesktopFiles(QStringList & list)249 List::addDesktopFiles(QStringList &list)
250 {
251 	entry_t *entry;
252 
253 	for (QString s : list) {
254 		DesktopFile df(s);
255 		if (df.read() == -1)
256 			continue;
257 		entry = dsbautostart_add_entry(as, df.cmd.toLocal8Bit().data(), true);
258 		if (entry == NULL) {
259 			qh_errx(this, EXIT_FAILURE, "%s",
260 			    dsbautostart_strerror());
261 		}
262 		List::addItem(entry);
263 	}
264 	compare();
265 }
266