1 /**************************************************************************
2 * Copyright (C) 2012 by Yuri Momotyuk *
3 * yurkis@gmail.com *
4 * Copyright (C) 2013 by Kris Moore *
5 * kris@pcbsd.org *
6 * *
7 * Permission is hereby granted, free of charge, to any person obtaining *
8 * a copy of this software and associated documentation files (the *
9 * "Software"), to deal in the Software without restriction, including *
10 * without limitation the rights to use, copy, modify, merge, publish, *
11 * distribute, sublicense, and/or sell copies of the Software, and to *
12 * permit persons to whom the Software is furnished to do so, subject to *
13 * the following conditions: *
14 * *
15 * The above copyright notice and this permission notice shall be *
16 * included in all copies or substantial portions of the Software. *
17 * *
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, *
19 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF *
20 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*
21 * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR *
22 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, *
23 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR *
24 * OTHER DEALINGS IN THE SOFTWARE. *
25 ***************************************************************************/
26
27 #include "mainwindow.h"
28 #include "ui_mainwindow.h"
29
30 #include <QInputDialog>
31 #include <QMessageBox>
32 #include <QTextStream>
33 #include <QProcess>
34 #include <QProcessEnvironment>
35 #include <QFile>
36 #include <QTextStream>
37 #include <QDir>
38
39 #define DM_CONFIG_FILE QString("/usr/local/etc/pcdm.conf")
40
41 ///////////////////////////////////////////////////////////////////////////////
toBoolean(QString Str,bool Default=false)42 inline bool toBoolean(QString Str, bool Default=false)
43 {
44 if (Str.trimmed().toLower() == "true")
45 return true;
46 if (Str.trimmed().toLower() == "false")
47 return false;
48 return Default;
49 }
50
51 ///////////////////////////////////////////////////////////////////////////////
fromBoolean(bool flag)52 inline QString fromBoolean(bool flag)
53 {
54 return (flag)?QString("true"):QString("false");
55 }
56
57 ///////////////////////////////////////////////////////////////////////////////
MainWindow(QWidget * parent)58 MainWindow::MainWindow(QWidget *parent) :
59 QMainWindow(parent),
60 ui(new Ui::MainWindow)
61 {
62 ui->setupUi(this);
63 exUserMenu = new QMenu(this);
64 ui->tool_exuser_add->setMenu(exUserMenu);
65 connect(exUserMenu, SIGNAL(triggered(QAction*)), this, SLOT(add_exuser(QAction*)) );
66 initUI();
67 }
68
69 ///////////////////////////////////////////////////////////////////////////////
~MainWindow()70 MainWindow::~MainWindow()
71 {
72 delete ui;
73 }
74
75 ///////////////////////////////////////////////////////////////////////////////
initUI()76 void MainWindow::initUI()
77 {
78
79 //Make sure the conf file exists
80 if(!QFile::exists(DM_CONFIG_FILE)){
81 qDebug() << "Copying over the default configuration file:" << DM_CONFIG_FILE;
82 if( !QFile::copy(DM_CONFIG_FILE+".dist", DM_CONFIG_FILE) ){
83 QMessageBox::warning(this,tr("Missing Config File"), QString(tr("The PCDM configuration file could not be found: %1")).arg(DM_CONFIG_FILE)+"\n\n"+tr("This application will now close"));
84 exit(1);
85 }
86 }
87 getUsers();
88 ui->UsersList->clear();
89 QString autoLogDelay = getValFromSHFile(DM_CONFIG_FILE, "AUTO_LOGIN_DELAY");
90 if(!autoLogDelay.isEmpty()){
91 ui->spin_autoLogDelay->setValue(autoLogDelay.toInt());
92 }
93
94 QString autoLogUser = getValFromSHFile(DM_CONFIG_FILE, "AUTO_LOGIN_USER");
95 for (int i=0; i<mvUsers.size(); i++)
96 {
97 ui->UsersList->addItem(mvUsers[i]);
98 if ( autoLogUser == mvUsers[i] )
99 ui->UsersList->setCurrentIndex(i);
100 }
101
102 QString autoLog = getValFromSHFile(DM_CONFIG_FILE, "ENABLE_AUTO_LOGIN");
103 if ( autoLog == "TRUE" ) {
104 ui->AutoLoginEnabledCB->setChecked(true);
105 ui->UsersList->setEnabled(true);
106 } else {
107 ui->AutoLoginEnabledCB->setChecked(false);
108 ui->UsersList->setEnabled(false);
109 }
110
111 ui->EnableVNC->setChecked(false);
112 QString vnc = getValFromSHFile(DM_CONFIG_FILE, "ALLOW_REMOTE_LOGIN");
113 if ( vnc == "TRUE" )
114 ui->EnableVNC->setChecked(true);
115
116 ui->checkShowPW->setChecked(false);
117 QString showpw = getValFromSHFile(DM_CONFIG_FILE, "ENABLE_VIEW_PASSWORD_BUTTON");
118 if ( showpw == "TRUE" )
119 ui->checkShowPW->setChecked(true);
120
121 ui->checkShowUsers->setChecked(true); //PCDM defaults to true
122 QString showusers = getValFromSHFile(DM_CONFIG_FILE, "SHOW_SYSTEM_USERS");
123 if( showusers != "TRUE" && !showusers.isEmpty() ){
124 ui->checkShowUsers->setChecked(false);
125 }
126
127 ui->checkAllowRoot->setChecked(false); //PCDM defaults to false
128 QString allowroot = getValFromSHFile(DM_CONFIG_FILE, "ALLOW_ROOT");
129 if(allowroot.toLower() == "true"){
130 ui->checkAllowRoot->setChecked(true);
131 }
132
133 ui->checkAllowStealth->setChecked(false); //PCDM defaults to false
134 QString allowstealth = getValFromSHFile(DM_CONFIG_FILE, "ALLOW_STEALTH_LOGIN");
135 if(allowstealth.toLower() == "true"){
136 ui->checkAllowStealth->setChecked(true);
137 }
138
139 ui->groupAllowUnder1K->setChecked(false); //PCDM defaults to false
140 QString allowU1K = getValFromSHFile(DM_CONFIG_FILE, "ALLOW_UID_UNDER_1K");
141 if(allowU1K.toLower() == "true"){
142 ui->groupAllowUnder1K->setChecked(true);
143 }
144 //Theme setting
145 loadAvailableThemes(); //update the combobox first
146 QString theme = getValFromSHFile(DM_CONFIG_FILE, "THEME_FILE");
147 int index = ui->combo_themes->findData(theme);
148 if(index>=0){ ui->combo_themes->setCurrentIndex(index); ui->radio_theme_bundle->setChecked(true); }
149 else{ ui->line_theme_custom->setText(theme); ui->radio_theme_custom->setChecked(true); }
150
151 //Update the UI appropriately
152 itemChanged();
153 ui->SaveButton->setEnabled(false); //re-disable the save button because nothing has changed yet
154
155
156
157 //Now setup all the signals/slots for updating the UI appropriately
158 connect( ui->AutoLoginEnabledCB, SIGNAL(stateChanged(int)), this, SLOT(itemChanged()) );
159 connect( ui->UsersList, SIGNAL(currentIndexChanged(int)), this, SLOT(itemChanged()) );
160 connect( ui->spin_autoLogDelay, SIGNAL(valueChanged(int)), this, SLOT(itemChanged()) );
161 connect( ui->EnableVNC, SIGNAL(stateChanged(int)), this, SLOT(itemChanged()) );
162 connect( ui->checkShowPW, SIGNAL(stateChanged(int)), this, SLOT(itemChanged()) );
163 connect( ui->checkShowUsers, SIGNAL(stateChanged(int)), this, SLOT(itemChanged()) );
164 connect(ui->checkAllowRoot, SIGNAL(stateChanged(int)), this, SLOT(itemChanged()) );
165 connect( ui->checkAllowStealth, SIGNAL(stateChanged(int)), this, SLOT(itemChanged()) );
166 connect( ui->groupAllowUnder1K, SIGNAL(toggled(bool)), this, SLOT(itemChanged()) );
167 connect( ui->radio_theme_bundle, SIGNAL(toggled(bool)), this, SLOT(itemChanged()) );
168 connect( ui->radio_theme_custom, SIGNAL(toggled(bool)), this, SLOT(itemChanged()) );
169 connect( ui->combo_themes, SIGNAL(currentIndexChanged(int)), this, SLOT(itemChanged()) );
170 connect( ui->line_exuser, SIGNAL(returnPressed()), this, SLOT(on_tool_exuser_add_clicked()) );
171 }
172
173 ///////////////////////////////////////////////////////////////////////////////
getUsers()174 void MainWindow::getUsers()
175 {
176 QStringList users = runShellCommand("getent passwd");
177 mvUsers.clear();
178 exUserMenu->clear();
179 for(int i=0; i<users.length(); i++){
180 QString line = users[i];
181 if ((line.trimmed().indexOf("#") != 0) && (! line.isEmpty())) { //Make sure it isn't a comment or blank
182 QString username = line.section(":",0,0);
183 QString homedir = line.section(":",5,5);
184 QString shell = line.section(":",6,6);
185 //Ignore invalid users
186 if(shell.contains("nologin") || homedir.contains("nonexistent") || homedir.endsWith("/empty") ){ continue; }
187
188 // Ignore PEFS encrypted users
189 if ( QFile::exists(homedir + "/.pefs.db") )
190 continue;
191
192 int uid = line.section(":",2,2).toInt();
193 if(uid==0){ continue; }
194 if ((uid>1000)&&(uid<65534)){
195 mvUsers.push_back(username);
196 }else if(QFile::exists(homedir) && QFile::exists(shell)){
197 exUserMenu->addAction(username);
198 }
199 }
200 }
201
202 /*QFile userFile("/etc/passwd");
203 if ( userFile.open(QIODevice::ReadOnly) ) {
204 QTextStream stream(&userFile);
205 stream.setCodec("UTF-8");
206 QString line;
207
208 while ( !stream.atEnd() ) {
209 line = stream.readLine();
210
211 if ((line.trimmed().indexOf("#") != 0) && (! line.isEmpty())) { //Make sure it isn't a comment or blank
212 QString username = line.section(":",0,0);
213 QString homedir = line.section(":",5,5);
214
215 // Ignore PEFS encrypted users
216 if ( QFile::exists(homedir + "/.pefs.db") )
217 continue;
218
219 int uid = line.section(":",2,2).toInt();
220 if ((uid>1000)&&(uid<65534))
221 mvUsers.push_back(username);
222 }//if gout user
223 }//for all lines
224 }//if can open file*/
225 }
226
227 ///////////////////////////////////////////////////////////////////////////////
getConfFileValue(QString oFile,QString Key)228 QString MainWindow::getConfFileValue( QString oFile, QString Key )
229 {
230 return getConfFileValue(oFile, Key, 1);
231 }
232
getConfFileValue(QString oFile,QString Key,int occur)233 QString MainWindow::getConfFileValue( QString oFile, QString Key, int occur )
234 {
235 int found = 1;
236
237 QFile file( oFile );
238 if ( ! file.open( QIODevice::ReadOnly ) ) {
239 return QString();
240 }
241
242 QTextStream stream( &file );
243 QString line;
244 while ( !stream.atEnd() ) {
245 line = stream.readLine(); // line of text excluding '\n'
246 line = line.section("#",0,0).trimmed(); //remove any comments
247 if(line.isEmpty()){ continue; }
248 int index = line.indexOf(Key, 0);
249 //qDebug() << "Line:" << line << index;
250 // If the KEY is not found at the start of the line, continue processing
251 if(index!=0)
252 continue;
253
254 if ( found == occur) {
255 line.remove(line.indexOf(Key, 0), Key.length());
256
257 // Remove any quotes
258 if ( line.indexOf('"') == 0 )
259 line = line.remove(0, 1);
260
261 if ( line.indexOf('"') != -1 )
262 line.truncate(line.indexOf('"'));
263
264 file.close();
265
266 return line;
267 } else {
268 found++;
269 }
270 }
271
272 file.close();
273 return QString();
274 }
275
276 ///////////////////////////////////////////////////////////////////////////////
setConfFileValue(QString oFile,QString oldKey,QString newKey)277 bool MainWindow::setConfFileValue( QString oFile, QString oldKey, QString newKey )
278 {
279 return setConfFileValue(oFile, oldKey, newKey, -1);
280 }
281
setConfFileValue(QString oFile,QString oldKey,QString newKey,int occur)282 bool MainWindow::setConfFileValue( QString oFile, QString oldKey, QString newKey, int occur )
283 {
284 // Lets the dev save a value into a specified config file.
285 // The occur value tells which occurance of "oldKey" to replace
286 // If occur is set to -1, it will remove any duplicates of "oldKey"
287
288 //copy the original file to create a temporary file for editing
289 QString oFileTmp = oFile + ".tmp";
290 QString cmd = "cp "+oFile+" "+oFileTmp;
291 runShellCommand(cmd);
292
293 //Continue evaluating the temporary file
294 QStringList SavedFile;
295 int found = 1;
296
297 // Load the old file, find the oldKey, remove it and replace with newKey
298 QFile file( oFileTmp );
299 if ( ! file.open( QIODevice::ReadOnly ) )
300 return false;
301
302 QTextStream stream( &file );
303 QString line;
304 while ( !stream.atEnd() ) {
305 line = stream.readLine(); // line of text excluding '\n'
306
307 // Key is not found at all
308 if ( line.indexOf(oldKey, 0) == -1 ) {
309 SavedFile << line ;
310 continue;
311 }
312
313 // Found the key, but it is commented out, so don't worry about this line
314 if ( line.trimmed().indexOf("#", 0) == 0 ) {
315 SavedFile << line ;
316 continue;
317 }
318
319 // If the KEY is found, and we are just on wrong occurance, save it and continue to search
320 if ( occur != -1 && found != occur ) {
321 SavedFile << line ;
322 found++;
323 continue;
324 }
325
326 // If the KEY is found in the line and this matches the occurance that must be processed
327 if ( ! newKey.isEmpty() && found == occur )
328 {
329 SavedFile << newKey ;
330 newKey.clear();
331 found++;
332 continue;
333 }
334
335 // If the KEY is found and we just want one occurance of the key
336 if ( occur == -1 && ! newKey.isEmpty() ) {
337 SavedFile << newKey ;
338 newKey.clear();
339 found++;
340 continue;
341 }
342
343 }
344
345 file.close();
346
347 // Didn't find the key? Write it!
348 if ( ! newKey.isEmpty() )
349 SavedFile << newKey;
350
351
352 // Save the new file
353 QFile fileout( oFileTmp );
354 if ( ! fileout.open( QIODevice::WriteOnly ) )
355 return false;
356
357 QTextStream streamout( &fileout );
358 for (int i = 0; i < SavedFile.size(); ++i)
359 streamout << SavedFile.at(i) << "\n";
360
361 fileout.close();
362
363 //Have the temporary file with new changes overwrite the original file
364 cmd = "mv "+oFileTmp+" "+oFile;
365 runShellCommand(cmd);
366
367 return true;
368
369 }
370
371 ///////////////////////////////////////////////////////////////////////////////
getValFromSHFile(QString envFile,QString envVal)372 QString MainWindow::getValFromSHFile(QString envFile, QString envVal)
373 {
374 QFile confFile(envFile);
375 if ( ! confFile.open( QIODevice::ReadOnly ) )
376 return "";
377
378 QTextStream stream( &confFile );
379 QString line;
380 while ( !stream.atEnd() ) {
381 line = stream.readLine();
382 if ( line.indexOf(envVal + "=") == 0 ) {
383 line.replace(envVal + "=", "");
384
385 // Remove the ' or " from variable
386 if ( line.indexOf("'") == 0 ) {
387 line = line.section("'", 1, 1);
388 line = line.section("'", 0, 0);
389 }
390 if ( line.indexOf('"') == 0 ) {
391 line = line.section('"', 1, 1);
392 line = line.section('"', 0, 0);
393 }
394
395 confFile.close();
396 return line.simplified();
397 }
398 }
399 confFile.close();
400
401 return QString();
402 }
403
404 ///////////////////////////////////////////////////////////////////////////////
runShellCommand(QString cmd)405 QStringList MainWindow::runShellCommand(QString cmd){
406 QProcess p;
407 //Make sure we use the system environment to properly read system variables, etc.
408 p.setProcessEnvironment(QProcessEnvironment::systemEnvironment());
409 //Merge the output channels to retrieve all output possible
410 p.setProcessChannelMode(QProcess::MergedChannels);
411 p.start(cmd);
412 while(p.state()==QProcess::Starting || p.state() == QProcess::Running){
413 p.waitForFinished(200);
414 QCoreApplication::processEvents();
415 }
416 QString tmp = p.readAllStandardOutput();
417 if(tmp.endsWith("\n")){ tmp.chop(1); }
418 return tmp.split("\n");
419 }
420
421 ///////////////////////////////////////////////////////////////////////////////
loadAvailableThemes()422 void MainWindow::loadAvailableThemes(){
423 ui->combo_themes->clear();
424 QDir themedir("/usr/local/share/PCDM/themes");
425 QStringList dirs = themedir.entryList(QDir::Dirs | QDir::NoDotAndDotDot, QDir::Name);
426 QStringList themefiles;
427 for(int i=0; i<dirs.length(); i++){
428 themedir.cd(dirs[i]);
429 QStringList files = themedir.entryList(QStringList() << "*.theme", QDir::Files, QDir::Name);
430 for(int j=0; j<files.length(); j++){ themefiles << themedir.absoluteFilePath(files[j]); }
431 themedir.cdUp();
432 }
433 //Now add the theme files to the combo box
434 for(int i=0; i<themefiles.length(); i++){
435 ui->combo_themes->addItem( themefiles[i].section("/",-1).section(".theme",0,-2), themefiles[i]);
436 }
437 }
438 ///////////////////////////////////////////////////////////////////////////////
on_SaveButton_clicked()439 void MainWindow::on_SaveButton_clicked()
440 {
441 bool ok;
442 system("touch " + DM_CONFIG_FILE.toLatin1());
443 if ( ui->AutoLoginEnabledCB->isChecked() && !ui->UsersList->currentText().isEmpty() ) {
444 // First ask for password
445 QString pw = QInputDialog::getText(this, tr("Password Request"),
446 tr("Please enter the login password for this user"),
447 QLineEdit::Password, "", &ok);
448 if ( ! ok )
449 return;
450
451 setConfFileValue(DM_CONFIG_FILE, "ENABLE_AUTO_LOGIN", "ENABLE_AUTO_LOGIN=TRUE", -1);
452 setConfFileValue(DM_CONFIG_FILE, "AUTO_LOGIN_USER", "AUTO_LOGIN_USER=" + ui->UsersList->currentText(), -1);
453 setConfFileValue(DM_CONFIG_FILE, "AUTO_LOGIN_PASSWORD", "AUTO_LOGIN_PASSWORD=" + pw, -1);
454 setConfFileValue(DM_CONFIG_FILE, "AUTO_LOGIN_DELAY","AUTO_LOGIN_DELAY="+QString::number(ui->spin_autoLogDelay->value()), -1);
455 } else {
456 ui->AutoLoginEnabledCB->setChecked(false); //make sure this is not checked to reflect file contents
457 setConfFileValue(DM_CONFIG_FILE, "ENABLE_AUTO_LOGIN", "ENABLE_AUTO_LOGIN=FALSE", -1);
458 setConfFileValue(DM_CONFIG_FILE, "AUTO_LOGIN_USER", "", -1);
459 setConfFileValue(DM_CONFIG_FILE, "AUTO_LOGIN_PASSWORD", "", -1);
460 setConfFileValue(DM_CONFIG_FILE, "AUTO_LOGIN_DELAY","", -1);
461 }
462
463 if ( ui->EnableVNC->isChecked() ) {
464 // First ask for password
465 QString pw = QInputDialog::getText(this, tr("Password Request"),
466 tr("Please enter the remote login password"),
467 QLineEdit::Password, "", &ok);
468 if ( ! ok )
469 return;
470
471 QFile file("/usr/local/etc/vncpass");
472 if (!file.open(QIODevice::WriteOnly | QIODevice::Text))
473 return;
474
475 QTextStream out(&file);
476 out << pw;
477 file.close();
478 system("chmod 600 /usr/local/etc/vncpass");
479
480 setConfFileValue(DM_CONFIG_FILE, "ALLOW_REMOTE_LOGIN", "ALLOW_REMOTE_LOGIN=TRUE", -1);
481 } else {
482 setConfFileValue(DM_CONFIG_FILE, "ALLOW_REMOTE_LOGIN", "ALLOW_REMOTE_LOGIN=FALSE", -1);
483 system("rm /usr/local/etc/vncpass 2>/dev/null");
484 }
485
486 if ( ui->checkShowPW->isChecked() )
487 setConfFileValue(DM_CONFIG_FILE, "ENABLE_VIEW_PASSWORD_BUTTON", "ENABLE_VIEW_PASSWORD_BUTTON=TRUE", -1);
488 else
489 setConfFileValue(DM_CONFIG_FILE, "ENABLE_VIEW_PASSWORD_BUTTON", "ENABLE_VIEW_PASSWORD_BUTTON=FALSE", -1);
490
491 if(ui->checkShowUsers->isChecked()){
492 setConfFileValue(DM_CONFIG_FILE, "SHOW_SYSTEM_USERS", "SHOW_SYSTEM_USERS=TRUE", -1);
493 }else{
494 setConfFileValue(DM_CONFIG_FILE, "SHOW_SYSTEM_USERS", "SHOW_SYSTEM_USERS=FALSE", -1);
495 }
496 if(ui->checkAllowRoot->isChecked()){
497 setConfFileValue(DM_CONFIG_FILE, "ALLOW_ROOT", "ALLOW_ROOT=TRUE", -1);
498 }else{
499 setConfFileValue(DM_CONFIG_FILE, "ALLOW_ROOT", "ALLOW_ROOT=FALSE", -1);
500 }
501 if(ui->checkAllowStealth->isChecked()){
502 setConfFileValue(DM_CONFIG_FILE, "ALLOW_STEALTH_LOGIN", "ALLOW_STEALTH_LOGIN=TRUE", -1);
503 }else{
504 setConfFileValue(DM_CONFIG_FILE, "ALLOW_STEALTH_LOGIN", "ALLOW_STEALTH_LOGIN=FALSE", -1);
505 }
506 if(ui->groupAllowUnder1K->isChecked()){
507 setConfFileValue(DM_CONFIG_FILE, "ALLOW_UID_UNDER_1K", "ALLOW_UID_UNDER_1K=TRUE", -1);
508 }else{
509 setConfFileValue(DM_CONFIG_FILE, "ALLOW_UID_UNDER_1K", "ALLOW_UID_UNDER_1K=FALSE", -1);
510 }
511 QStringList exusers;
512 for(int i=0; i<ui->list_exuser->count(); i++){
513 exusers << ui->list_exuser->item(i)->text();
514 }
515 exusers.removeDuplicates();
516 setConfFileValue(DM_CONFIG_FILE,"EXCLUDED_USERS", "EXCLUDED_USERS="+exusers.join(","), -1);
517
518 QString theme;
519 if(ui->radio_theme_bundle->isChecked()){
520 theme = ui->combo_themes->currentData().toString();
521 }else{
522 theme = ui->line_theme_custom->text();
523 }
524 if(!theme.isEmpty()){ setConfFileValue(DM_CONFIG_FILE,"THEME_FILE", "THEME_FILE="+theme, -1); }
525
526 // Lastly make sure we set perms
527 system("chmod 600 " + DM_CONFIG_FILE.toLatin1());
528 ui->SaveButton->setEnabled(false);
529 }
530
531
532 ///////////////////////////////////////////////////////////////////////////////
slotSingleInstance()533 void MainWindow::slotSingleInstance()
534 {
535 this->hide();
536 this->showNormal();
537 this->activateWindow();
538 this->raise();
539 }
540
541 /////////////////////////////////////////////////
itemChanged()542 void MainWindow::itemChanged(){
543 ui->SaveButton->setEnabled(true);
544 //Double check the dependant options for whether they are possible to be changed
545 ui->UsersList->setEnabled( ui->AutoLoginEnabledCB->isChecked() );
546 ui->spin_autoLogDelay->setEnabled( ui->AutoLoginEnabledCB->isChecked() );
547 }
548
on_tool_exuser_rem_clicked()549 void MainWindow::on_tool_exuser_rem_clicked(){
550 QList<QListWidgetItem*> sel = ui->list_exuser->selectedItems();
551 for(int i=0; i<sel.length(); i++){
552 delete sel[i];
553 }
554 itemChanged();
555 }
556
on_tool_exuser_add_clicked()557 void MainWindow::on_tool_exuser_add_clicked(){
558 QString name = ui->line_exuser->text();
559 ui->line_exuser->setText("");
560 name = name.remove(" ");
561 if(name.isEmpty() || !ui->list_exuser->findItems(name,Qt::MatchExactly).isEmpty() ){ return; }
562 ui->list_exuser->addItem(name);
563 itemChanged();
564 }
565
add_exuser(QAction * act)566 void MainWindow::add_exuser(QAction* act){ //for a username selected from the menu
567 if( !ui->list_exuser->findItems(act->text(), Qt::MatchExactly).isEmpty() ){ return; }
568 ui->list_exuser->addItem(act->text());
569 itemChanged();
570 }
571