ViewVC Help
View File | Revision Log | View Changeset | Root Listing
root/Oni2/s10k/CommonUtils/util.cpp
(Generate patch)

Comparing s10k/CommonUtils/util.cpp (file contents):
Revision 1095 by s10k, Sat Dec 30 14:30:28 2017 UTC vs.
Revision 1109 by s10k, Sat Feb 16 17:23:09 2019 UTC

# Line 1 | Line 1
1 < /**
2 < * Copyright (C) 2017 - Fábio Bento (random-guy)
3 < *
4 < * This library is distributed under the MIT License. See notice at the end
5 < * of this file.
6 < *
7 < */
8 <
9 < #include "util.h"
10 <
11 < namespace Util{
12 <
13 < namespace FileSystem {
14 <
15 < QString normalizePath(QString path){
16 <    return path.replace("\\","/");
17 < }
18 <
19 < QString cutName(QString path){
20 <    return path.remove(0,path.lastIndexOf('/')).remove('"');
21 < }
22 <
23 < QString cutNameWithoutBackSlash(QString path){
24 <    return cutName(path).remove('/');
25 < }
26 <
27 < QString normalizeAndQuote(QString path){
28 <    return String::insertQuotes(normalizePath(path));
29 < }
30 <
31 < // Created from scratch
32 < bool copyDir(const QString &fromPath, QString toPath, const bool isRecursive){
33 <    QDir fromDir(fromPath);
34 <    QDir toDir(toPath);
35 <
36 <    if(!toDir.mkdir(fromDir.dirName())){ // create the folder in the destination
37 <        return false;
38 <    }
39 <
40 <    // Update toPath to include the folder from "fromPath"
41 <    toPath = toPath + "/" + fromDir.dirName();
42 <    toDir = QDir(toPath);
43 <
44 <    for(const QFileInfo &currFileInfo : fromDir.entryInfoList(QDir::Dirs | QDir::Files | QDir::NoDotAndDotDot)){
45 <
46 <        if(currFileInfo.isFile()){
47 <
48 <            QFile destFile(toPath + "/" + currFileInfo.fileName());
49 <
50 <            if(!QFile::copy(currFileInfo.absoluteFilePath(),toPath + "/" + currFileInfo.fileName())){
51 <                return false;
52 <            }
53 <        }
54 <        else if(isRecursive && currFileInfo.isDir() && currFileInfo.absoluteFilePath() != fromDir.absolutePath()){
55 <
56 <            if(!copyDir(currFileInfo.absoluteFilePath(), toPath, isRecursive)){
57 <                return false;
58 <            }
59 <        }
60 <    }
61 <
62 <    return true;
63 < }
64 <
65 < //Copied from here: http://stackoverflow.com/questions/2536524/copy-directory-using-qt (ty roop)
66 < bool rmDir(const QString &dirPath)
67 < {
68 <    QDir dir(dirPath);
69 <    if (!dir.exists())
70 <        return true;
71 <    for(const QFileInfo &info : dir.entryInfoList(QDir::Dirs | QDir::Files | QDir::NoDotAndDotDot)) {
72 <        if (info.isDir()) {
73 <            if (!rmDir(info.filePath()))
74 <                return false;
75 <        } else {
76 <            if (!dir.remove(info.fileName()))
77 <                return false;
78 <        }
79 <    }
80 <    QDir parentDir(QFileInfo(dirPath).path());
81 <    return parentDir.rmdir(QFileInfo(dirPath).fileName());
82 < }
83 <
84 < // Gets all files from a folder filtered by a given wildcard
85 < QStringList getFolderFilesByWildcard(const QString &entryFolder, const QString &wildcard, bool isRecursive){
86 <
87 <    QStringList filesFound; // result files with absolute path
88 <
89 <    QDirIterator it(entryFolder, QDir::Files, (isRecursive ? QDirIterator::Subdirectories : QDirIterator::NoIteratorFlags));
90 <
91 <    while (it.hasNext()){
92 <        filesFound << it.next();
93 <    }
94 <
95 <    return filterFilesByWildcard(filesFound, wildcard);
96 < }
97 <
98 < // Supports wildcards, and subdirectories with wildcard e.g.:
99 < // *.xml
100 < // /myXmls/*.xml
101 < //
102 < // online helper: https://regex101.com/
103 < QStringList filterFilesByWildcard(const QStringList &filePaths, const QString &wildcard){
104 <    QStringList resultFiles;
105 <    QString formattedWildcard;
106 <
107 <    if(wildcard.trimmed().isEmpty()){
108 <        return resultFiles;
109 <    }
110 <
111 <    formattedWildcard=normalizePath(wildcard); // Convert slashes to work in both mac and windows
112 <
113 <    // escape the string so '.' or '(' chars get correctly escaped
114 <    formattedWildcard = QRegularExpression::escape(formattedWildcard);
115 <
116 <    // replace * by the corresponding regex
117 <    formattedWildcard.replace("\\*",".*");
118 <
119 <    // replace ? by the corresponding regex
120 <    formattedWildcard.replace("\\?",".");
121 <
122 <    // if it doesn't start with any regex wildcard or a subdirectory slash, add a slash to beginning (so the file/folder matches at least the root folder)
123 <    // We use \\/ instead of / because it was escaped
124 <    if(!formattedWildcard.startsWith("\\/") && !formattedWildcard.startsWith(".*") && !formattedWildcard.startsWith(".")){
125 <        formattedWildcard = "\\/" + formattedWildcard;
126 <    }
127 <
128 <    // if it is a subdirectory add * to match
129 <    if(formattedWildcard.startsWith("\\/")){
130 <        formattedWildcard = ".*" + formattedWildcard;
131 <    }
132 <
133 <    formattedWildcard = "^" + formattedWildcard + "$"; // we want a full match (http://stackoverflow.com/a/5752852)
134 <
135 <    QRegularExpression regex(formattedWildcard);
136 <
137 <    for(const QString &currentFile : filePaths){
138 <
139 <        if(regex.match(currentFile).hasMatch()){
140 <            resultFiles << currentFile;
141 <        }
142 <
143 <    }
144 <
145 <    return resultFiles;
146 < }
147 <
148 < // Returns empty QString on failure.
149 < // Based from here: http://www.qtcentre.org/archive/index.php/t-35674.html (thanks wysota!)
150 < QString fileHash(const QString &fileName, QCryptographicHash::Algorithm hashAlgorithm)
151 < {
152 <
153 <    QCryptographicHash crypto(hashAlgorithm);
154 <    QFile file(fileName);
155 <    file.open(QFile::ReadOnly);
156 <    while(!file.atEnd()){
157 <        crypto.addData(file.read(8192));
158 <    }
159 <    QByteArray hash = crypto.result();
160 <
161 <    return QString(crypto.result().toHex());
162 <
163 < }
164 <
165 <
166 < /**
167 <  Gets application directory. In mac os gets the .app directory
168 <  **/
169 < QString getAppPath(){
170 < #ifdef Q_OS_MAC
171 <    QDir dir = QDir(QCoreApplication::applicationDirPath());
172 <    if(dir.absolutePath().contains(".app")){ // include bundle, but we don't want it
173 <        dir.cdUp();
174 <        dir.cdUp();
175 <        dir.cdUp();
176 <    }
177 <    return dir.absolutePath();
178 < #else
179 <    return  QDir::currentPath();
180 < #endif
181 < }
182 <
183 < bool backupFile(const QString &file, QString newFilename){
184 <        
185 <        if(newFilename.isEmpty()){
186 <                newFilename = file;
187 <        }
188 <        
189 <    return QFile::copy(file, newFilename+".bak");
190 < }
191 <
192 < }
193 <
194 < namespace String {
195 <
196 < QString insertApostrophes(const QString &currString){
197 <    return "'"+currString+"'";
198 < }
199 <
200 < QString insertQuotes(const QString &currString){
201 <    return "\""+currString+"\"";
202 < }
203 <
204 < QString fullTrim(QString str) {
205 <
206 <    str = str.simplified(); //convert all invisible chars in normal whitespaces
207 <    str.replace( " ", "" );
208 <
209 <    return str;
210 < }
211 <
212 < QStringList substring(QString myString, QString separator, Qt::CaseSensitivity cs){
213 <    QStringList result = QStringList();
214 <    int currIdx=0, nextIdx=0;
215 <
216 <    while(true){
217 <        nextIdx=myString.indexOf(separator,currIdx,cs);
218 <        result << myString.mid(currIdx,nextIdx-currIdx);
219 <        if(nextIdx==-1) break;
220 <        currIdx=nextIdx+1;
221 <    }
222 <
223 <    return result;
224 < }
225 <
226 < QString normalizeDecimalSeparator(QString value){
227 <    return value.replace(',','.');
228 < }
229 <
230 < //Searches for the QString "toSearch" in the "myString" variable backward
231 < //Returns the index of the first match or -1 if not found
232 < int indexOfBackward(QString myString, QString toSearch, int from){
233 <    int myStringSize=myString.size();
234 <    int toSearchSize=toSearch.size();
235 <
236 <    if(from==-1){
237 <        from=myStringSize;
238 <    }
239 <
240 <    int i=from;
241 <
242 <    while(i>=0){
243 <        for(int j=toSearchSize-1; j>=0; j--){
244 <            i--;
245 <            if(myString.at(i)!=toSearch.at(j)){
246 <                break;
247 <            }
248 <            if(j==0){
249 <                return i;
250 <            }
251 <        }
252 <    }
253 <
254 <    return -1;
255 < }
256 <
257 < // no problem here with "temporary" cstr
258 < // https://stackoverflow.com/questions/1971183/when-does-c-allocate-deallocate-string-literals
259 < const char* boolToCstr(bool currentBoolean){
260 <    return currentBoolean ? "true" : "false";
261 < }
262 <
263 < }
264 <
265 < #ifdef QT_GUI_LIB
266 < namespace Dialogs {
267 <
268 < void showInfo(const QString &message){
269 <    QMessageBox msgBox;
270 <    msgBox.setIcon(QMessageBox::Information);
271 <    msgBox.setText(message);
272 <    msgBox.exec();
273 < }
274 <
275 < void showRichInfo(const QString &message){
276 <    QMessageBox msgBox;
277 <    msgBox.setTextFormat(Qt::RichText);
278 <    msgBox.setIcon(QMessageBox::Information);
279 <    msgBox.setText(message);
280 <    msgBox.exec();
281 < }
282 <
283 < void showWarning(const QString &message){
284 <    QMessageBox msgBox;
285 <    msgBox.setIcon(QMessageBox::Warning);
286 <    msgBox.setText(message);
287 <    msgBox.exec();
288 < }
289 <
290 < void showError(const QString &message){
291 <    QMessageBox msgBox;
292 <    msgBox.setIcon(QMessageBox::Critical);
293 <    msgBox.setText(message);
294 <    msgBox.exec();
295 < }
296 <
297 < void showRichError(const QString &message){
298 <    QMessageBox msgBox;
299 <    msgBox.setIcon(QMessageBox::Critical);
300 <    msgBox.setText(message);
301 <    msgBox.exec();
302 < }
303 <
304 < bool showQuestion(QWidget * parent, QString message, QMessageBox::StandardButton standardButton){
305 <    return QMessageBox::question (parent, "Are you sure?", message, QMessageBox::Yes | QMessageBox::No, standardButton)==QMessageBox::Yes;
306 < }
307 <
308 < QMessageBox::StandardButton showQuestionWithCancel(QWidget * parent, QString message, QMessageBox::StandardButton standardButton){
309 <    return QMessageBox::question (parent, "Are you sure?", message, QMessageBox::Yes | QMessageBox::No | QMessageBox::Cancel, standardButton);
310 < }
311 <
312 < QStringList multipleDirSelection(const QString &title){
313 <    QFileDialog w;
314 <
315 <    // We need to use non native dialog, because native doesn't support multiple folder selection
316 <    w.setOption(QFileDialog::DontUseNativeDialog,true);
317 <
318 <    w.setFileMode(QFileDialog::DirectoryOnly);
319 <
320 <    w.setWindowTitle(title);
321 <
322 <    QTreeView *t = w.findChild<QTreeView*>();
323 <
324 <    if (t) {
325 <        t->setSelectionMode(QAbstractItemView::MultiSelection);
326 <    }
327 <
328 <    if(w.exec()){ //if accepted
329 <        return w.selectedFiles();
330 <    }
331 <    return QStringList(); //return empty
332 < }
333 <
334 < }
335 < #endif
336 <
337 < namespace Validation {
338 <
339 < // Check if any string in the list is empty
340 < bool checkEmptySpaces(QStringList toCheck){
341 <    for (const QString &current : toCheck){
342 <        if(current.trimmed().isEmpty()){
343 <            return true; //There are empty spaces
344 <        }
345 <    }
346 <    return false;
347 < }
348 <
349 < bool checkIfIntegers(QStringList toCheck){
350 <    for (const QString &current : toCheck){
351 <        if(!isStringInteger(current)){
352 <            return true; // Some aren't valid integers
353 <        }
354 <    }
355 <    return false;
356 < }
357 <
358 < bool checkIfDoubles(QStringList toCheck){
359 <    for (const QString &current : toCheck){
360 <        if(!isStringDouble(current)){
361 <            return true; // Some aren't valid doubles
362 <        }
363 <    }
364 <    return false;
365 < }
366 <
367 < bool isStringInteger(QString myString){
368 <    bool isNumber;
369 <
370 <    myString.toInt(&isNumber); //convert to int and see if it succeeds
371 <
372 <    return isNumber;
373 < }
374 <
375 < bool isStringDouble(QString myString){
376 <    bool isDouble;
377 <
378 <    myString.toDouble(&isDouble); //convert to double and see if it succeeds
379 <
380 <    return isDouble;
381 < }
382 <
383 < }
384 <
385 < namespace System {
386 <
387 < #ifdef QT_GUI_LIB
388 < // From here: http://stackoverflow.com/questions/17893328/qt-getting-the-screen-resolution-without-the-extended-monitor ty Chris
389 < QRect getScreenResolution(){
390 <    QDesktopWidget widget;
391 <    return widget.availableGeometry(widget.primaryScreen()); // or screenGeometry(), depending on your needs
392 < }
393 < #endif
394 <
395 < }
396 <
397 < #ifdef QT_GUI_LIB
398 < namespace TableWidget {
399 <
400 <
401 < void addRow(QTableWidget *myTable, QStringList &columns){
402 <    //Get actual number rows
403 <    int twSize=myTable->rowCount();
404 <
405 <    //increase the rows for the new item
406 <    myTable->setRowCount(twSize+1);
407 <
408 <    //Add to table and list to
409 <    for(int i=0; i<columns.size(); i++){
410 <        QTableWidgetItem *newColumn = new QTableWidgetItem(columns[i]);
411 <        myTable->setItem(twSize,i,newColumn);
412 <        // Add a tooltip with with the cell content
413 <        myTable->item(twSize,i)->setToolTip(myTable->item(twSize,i)->text());
414 <    }
415 <
416 < }
417 <
418 <
419 < QModelIndexList getSelectedRows(QTableWidget *myTable){
420 <    return myTable->selectionModel()->selectedRows();
421 < }
422 <
423 < QModelIndexList getCurrentRows(QTableWidget *myTable){
424 <
425 <    QModelIndexList oldSelection = getSelectedRows(myTable);
426 <
427 <    myTable->selectAll();
428 <
429 <    QModelIndexList allRows = getSelectedRows(myTable);
430 <
431 <    myTable->selectionModel()->clearSelection();
432 <
433 <    // Restore old selection
434 <    for(const QModelIndex &currentIndex : oldSelection){
435 <        myTable->selectionModel()->select(currentIndex, QItemSelectionModel::Select | QItemSelectionModel::SelectionFlag::Rows);
436 <    }
437 <
438 <    return allRows;
439 < }
440 <
441 < int getNumberSelectedRows(QTableWidget *myTable){
442 <    return getSelectedRows(myTable).size();
443 < }
444 <
445 < void clearContents(QTableWidget *myTable, const QString &nothingToClearMessage, const QString &questionToClear){
446 <
447 <    if(myTable->rowCount()==0){
448 <        Dialogs::showInfo(nothingToClearMessage);
449 <        return;
450 <    }
451 <
452 <    if(Dialogs::showQuestion(myTable, questionToClear)){
453 <        clearContentsNoPrompt(myTable);
454 <    }
455 <
456 < }
457 <
458 < void clearContentsNoPrompt(QTableWidget *myTable){
459 <    myTable->clearContents();
460 <    myTable->setRowCount(0);
461 < }
462 <
463 < // Adapted from here:
464 < // http://stackoverflow.com/questions/29176317/qtablewidget-checkbox-get-state-and-location
465 < void addCheckBox(QTableWidget *myTable, int row, int column, QCheckBox *checkbox){
466 <    if(checkbox == nullptr){
467 <        checkbox = new QCheckBox();
468 <    }
469 <
470 <    QWidget *auxLayoutWidget = new QWidget(myTable);
471 <
472 <    QHBoxLayout* checkBoxLayout = new QHBoxLayout();
473 <    checkBoxLayout->setContentsMargins(0,0,0,0);
474 <    checkBoxLayout->addWidget(checkbox);
475 <    checkBoxLayout->setAlignment(Qt::AlignCenter);
476 <    checkBoxLayout->setSpacing(0);
477 <    auxLayoutWidget->setLayout(checkBoxLayout);
478 <
479 <    myTable->setCellWidget(row, column, auxLayoutWidget);
480 < }
481 <
482 < // Adapted from here:
483 < // http://stackoverflow.com/questions/29176317/qtablewidget-checkbox-get-state-and-location
484 < QCheckBox* getCheckBoxFromCell(QTableWidget *myTable, int row, int column){
485 <    return dynamic_cast<QCheckBox*>(myTable->cellWidget(row, column)->findChild<QCheckBox *>());
486 < }
487 <
488 < // Adapted from here:
489 < // http://www.qtcentre.org/threads/3386-QTableWidget-move-row
490 < // Thanks jpn
491 < void swapRows(QTableWidget *myTable, const int indexSourceRow, const int indexDestinationRow, bool selectSwappedRow)
492 < {
493 <    // takes and returns the whole row
494 <    auto takeRow = [&myTable](int row) -> QList<QTableWidgetItem*>
495 <    {
496 <        QList<QTableWidgetItem*> rowItems;
497 <        for (int col = 0; col < myTable->columnCount(); ++col)
498 <        {
499 <            rowItems << myTable->takeItem(row, col);
500 <        }
501 <        return rowItems;
502 <    };
503 <
504 <    // sets the whole row
505 <    auto setRow = [&myTable](int row, const QList<QTableWidgetItem*>& rowItems)
506 <    {
507 <        for (int col = 0; col < myTable->columnCount(); ++col)
508 <        {
509 <            myTable->setItem(row, col, rowItems.at(col));
510 <        }
511 <    };
512 <
513 <    // take whole rows
514 <    QList<QTableWidgetItem*> sourceItems = takeRow(indexSourceRow);
515 <    QList<QTableWidgetItem*> destItems = takeRow(indexDestinationRow);
516 <
517 <    // set back in reverse order
518 <    setRow(indexSourceRow, destItems);
519 <    setRow(indexDestinationRow, sourceItems);
520 <
521 <    if(selectSwappedRow){
522 <        myTable->selectRow(indexDestinationRow);
523 <    }
524 < }
525 <
526 < void deleteSelectedRows(QTableWidget *myTable){
527 <    int size = myTable->selectionModel()->selectedRows().size();
528 <
529 <    for(int i=0; i<size; i++){
530 <        myTable->removeRow(myTable->selectionModel()->selectedRows().at(size-i-1).row());
531 <    }
532 < }
533 <
534 < }
535 < #endif
536 <
537 < #ifdef QT_GUI_LIB
538 < namespace StatusBar {
539 <
540 < void showError(QStatusBar * const statusBar, const QString &message){
541 <
542 <    QPalette myPalete = QPalette();
543 <    myPalete.setColor( QPalette::WindowText, QColor(255,0,0));
544 <    statusBar->setPalette( myPalete );
545 <    statusBar->showMessage(message,10000); //display by 10 seconds
546 <
547 < }
548 <
549 < void showSuccess(QStatusBar * const statusBar,const QString &message){
550 <
551 <    QPalette myPalete = QPalette();
552 <    myPalete.setColor( QPalette::WindowText, QColor(0,150,0));
553 <    statusBar->setPalette( myPalete );
554 <    statusBar->showMessage(message,10000); //display by 10 seconds
555 <
556 < }
557 <
558 < }
559 < #endif
560 <
561 < }
562 <
563 <
564 < /**
565 < * Copyright (c) 2017 - Fábio Bento (random-guy)
566 < *
567 < * Permission is hereby granted, free of charge, to any person
568 < * obtaining a copy of this software and associated documentation
569 < * files (the "Software"), to deal in the Software without
570 < * restriction, including without limitation the rights to use,
571 < * copy, modify, merge, publish, distribute, sublicense, and/or sell
572 < * copies of the Software, and to permit persons to whom the
573 < * Software is furnished to do so, subject to the following
574 < * conditions:
575 < *
576 < * The above copyright notice and this permission notice shall be
577 < * included in all copies or substantial portions of the Software.
578 < *
579 < * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
580 < * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
581 < * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
582 < * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
583 < * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
584 < * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
585 < * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
586 < * OTHER DEALINGS IN THE SOFTWARE.
587 < */
1 > /**
2 > * Copyright (C) 2017 - 2018 Fábio Bento (fabiobento512)
3 > *
4 > * This library is distributed under the MIT License. See notice at the end
5 > * of this file.
6 > *
7 > */
8 >
9 > #include "util.h"
10 >
11 > namespace Util{
12 >
13 > namespace FileSystem {
14 >
15 > QString normalizePath(QString path){
16 >    return path.replace("\\","/");
17 > }
18 >
19 > QString cutName(QString path){
20 >    return path.remove(0,path.lastIndexOf('/')).remove('"');
21 > }
22 >
23 > QString cutNameWithoutBackSlash(QString path){
24 >    return cutName(path).remove('/');
25 > }
26 >
27 > QString normalizeAndQuote(QString path){
28 >    return String::insertQuotes(normalizePath(path));
29 > }
30 >
31 > // Created from scratch
32 > bool copyDir(const QString &fromPath, QString toPath, const bool isRecursive){
33 >    QDir fromDir(fromPath);
34 >    QDir toDir(toPath);
35 >
36 >    if(!toDir.mkdir(fromDir.dirName())){ // create the folder in the destination
37 >        return false;
38 >    }
39 >
40 >    // Update toPath to include the folder from "fromPath"
41 >    toPath = toPath + "/" + fromDir.dirName();
42 >    toDir = QDir(toPath);
43 >
44 >    for(const QFileInfo &currFileInfo : fromDir.entryInfoList(QDir::Dirs | QDir::Files | QDir::NoDotAndDotDot)){
45 >
46 >        if(currFileInfo.isFile()){
47 >
48 >            QFile destFile(toPath + "/" + currFileInfo.fileName());
49 >
50 >            if(!QFile::copy(currFileInfo.absoluteFilePath(),toPath + "/" + currFileInfo.fileName())){
51 >                return false;
52 >            }
53 >        }
54 >        else if(isRecursive && currFileInfo.isDir() && currFileInfo.absoluteFilePath() != fromDir.absolutePath()){
55 >
56 >            if(!copyDir(currFileInfo.absoluteFilePath(), toPath, isRecursive)){
57 >                return false;
58 >            }
59 >        }
60 >    }
61 >
62 >    return true;
63 > }
64 >
65 > //Copied from here: http://stackoverflow.com/questions/2536524/copy-directory-using-qt (ty roop)
66 > bool rmDir(const QString &dirPath)
67 > {
68 >    QDir dir(dirPath);
69 >    if (!dir.exists())
70 >        return true;
71 >    for(const QFileInfo &info : dir.entryInfoList(QDir::Dirs | QDir::Files | QDir::NoDotAndDotDot)) {
72 >        if (info.isDir()) {
73 >            if (!rmDir(info.filePath()))
74 >                return false;
75 >        } else {
76 >            if (!dir.remove(info.fileName()))
77 >                return false;
78 >        }
79 >    }
80 >    QDir parentDir(QFileInfo(dirPath).path());
81 >    return parentDir.rmdir(QFileInfo(dirPath).fileName());
82 > }
83 >
84 > // Gets all files from a folder filtered by a given wildcard
85 > QStringList getFolderFilesByWildcard(const QString &entryFolder, const QString &wildcard, bool isRecursive){
86 >
87 >    QStringList filesFound; // result files with absolute path
88 >
89 >    QDirIterator it(entryFolder, QDir::Files, (isRecursive ? QDirIterator::Subdirectories : QDirIterator::NoIteratorFlags));
90 >
91 >    while (it.hasNext()){
92 >        filesFound << it.next();
93 >    }
94 >
95 >    return filterFilesByWildcard(filesFound, wildcard);
96 > }
97 >
98 > // Supports wildcards, and subdirectories with wildcard e.g.:
99 > // *.xml
100 > // /myXmls/*.xml
101 > //
102 > // online helper: https://regex101.com/
103 > QStringList filterFilesByWildcard(const QStringList &filePaths, const QString &wildcard){
104 >    QStringList resultFiles;
105 >    QString formattedWildcard;
106 >
107 >    if(wildcard.trimmed().isEmpty()){
108 >        return resultFiles;
109 >    }
110 >
111 >    formattedWildcard=normalizePath(wildcard); // Convert slashes to work in both mac and windows
112 >
113 >    // escape the string so '.' or '(' chars get correctly escaped
114 >    formattedWildcard = QRegularExpression::escape(formattedWildcard);
115 >
116 >    // replace * by the corresponding regex
117 >    formattedWildcard.replace("\\*",".*");
118 >
119 >    // replace ? by the corresponding regex
120 >    formattedWildcard.replace("\\?",".");
121 >
122 >    // if it doesn't start with any regex wildcard or a subdirectory slash, add a slash to beginning (so the file/folder matches at least the root folder)
123 >    // We use \\/ instead of / because it was escaped
124 >    if(!formattedWildcard.startsWith("\\/") && !formattedWildcard.startsWith(".*") && !formattedWildcard.startsWith(".")){
125 >        formattedWildcard = "\\/" + formattedWildcard;
126 >    }
127 >
128 >    // if it is a subdirectory add * to match
129 >    if(formattedWildcard.startsWith("\\/")){
130 >        formattedWildcard = ".*" + formattedWildcard;
131 >    }
132 >
133 >    formattedWildcard = "^" + formattedWildcard + "$"; // we want a full match (http://stackoverflow.com/a/5752852)
134 >
135 >    QRegularExpression regex(formattedWildcard);
136 >
137 >    for(const QString &currentFile : filePaths){
138 >
139 >        if(regex.match(currentFile).hasMatch()){
140 >            resultFiles << currentFile;
141 >        }
142 >
143 >    }
144 >
145 >    return resultFiles;
146 > }
147 >
148 > // Returns empty QString on failure.
149 > // Based from here: http://www.qtcentre.org/archive/index.php/t-35674.html (thanks wysota!)
150 > QString fileHash(const QString &fileName, QCryptographicHash::Algorithm hashAlgorithm)
151 > {
152 >
153 >    QCryptographicHash crypto(hashAlgorithm);
154 >    QFile file(fileName);
155 >    file.open(QFile::ReadOnly);
156 >    while(!file.atEnd()){
157 >        crypto.addData(file.read(8192));
158 >    }
159 >    QByteArray hash = crypto.result();
160 >
161 >    return QString(crypto.result().toHex());
162 >
163 > }
164 >
165 >
166 > /**
167 >  Gets application directory. In mac os gets the .app directory
168 >  **/
169 > QString getAppPath(){
170 > #ifdef Q_OS_MAC
171 >    QDir dir = QDir(QCoreApplication::applicationDirPath());
172 >    if(dir.absolutePath().contains(".app")){ // include bundle, but we don't want it
173 >        dir.cdUp();
174 >        dir.cdUp();
175 >        dir.cdUp();
176 >    }
177 >    return dir.absolutePath();
178 > #else
179 >    return  QDir::currentPath();
180 > #endif
181 > }
182 >
183 > bool backupFile(const QString &file, QString newFilename){
184 >        
185 >        if(newFilename.isEmpty()){
186 >                newFilename = file;
187 >        }
188 >        
189 >    return QFile::copy(file, newFilename+".bak");
190 > }
191 >
192 > }
193 >
194 > namespace String {
195 >
196 > QString insertApostrophes(const QString &currString){
197 >    return "'"+currString+"'";
198 > }
199 >
200 > QString insertQuotes(const QString &currString){
201 >    return "\""+currString+"\"";
202 > }
203 >
204 > QString fullTrim(QString str) {
205 >
206 >    str = str.simplified(); //convert all invisible chars in normal whitespaces
207 >    str.replace( " ", "" );
208 >
209 >    return str;
210 > }
211 >
212 > QStringList substring(QString myString, QString separator, Qt::CaseSensitivity cs){
213 >    QStringList result = QStringList();
214 >    int currIdx=0, nextIdx=0;
215 >
216 >    while(true){
217 >        nextIdx=myString.indexOf(separator,currIdx,cs);
218 >        result << myString.mid(currIdx,nextIdx-currIdx);
219 >        if(nextIdx==-1) break;
220 >        currIdx=nextIdx+1;
221 >    }
222 >
223 >    return result;
224 > }
225 >
226 > QString normalizeDecimalSeparator(QString value){
227 >    return value.replace(',','.');
228 > }
229 >
230 > //Searches for the QString "toSearch" in the "myString" variable backward
231 > //Returns the index of the first match or -1 if not found
232 > int indexOfBackward(QString myString, QString toSearch, int from){
233 >    int myStringSize=myString.size();
234 >    int toSearchSize=toSearch.size();
235 >
236 >    if(from==-1){
237 >        from=myStringSize;
238 >    }
239 >
240 >    int i=from;
241 >
242 >    while(i>=0){
243 >        for(int j=toSearchSize-1; j>=0; j--){
244 >            i--;
245 >            if(myString.at(i)!=toSearch.at(j)){
246 >                break;
247 >            }
248 >            if(j==0){
249 >                return i;
250 >            }
251 >        }
252 >    }
253 >
254 >    return -1;
255 > }
256 >
257 > // no problem here with "temporary" cstr
258 > // https://stackoverflow.com/questions/1971183/when-does-c-allocate-deallocate-string-literals
259 > const char* boolToCstr(bool currentBoolean){
260 >    return currentBoolean ? "true" : "false";
261 > }
262 >
263 > }
264 >
265 > #ifdef QT_GUI_LIB
266 > namespace Dialogs {
267 >
268 > void showInfo(const QString &message, const bool richText){
269 >    QMessageBox msgBox;
270 >        if(richText){
271 >                msgBox.setTextFormat(Qt::RichText);
272 >        }
273 >    msgBox.setIcon(QMessageBox::Information);
274 >    msgBox.setText(message);
275 >    msgBox.exec();
276 > }
277 >
278 > void showWarning(const QString &message, const bool richText){
279 >    QMessageBox msgBox;
280 >        if(richText){
281 >                msgBox.setTextFormat(Qt::RichText);
282 >        }
283 >    msgBox.setIcon(QMessageBox::Warning);
284 >    msgBox.setText(message);
285 >    msgBox.exec();
286 > }
287 >
288 > void showError(const QString &message, const bool richText){
289 >    QMessageBox msgBox;
290 >        if(richText){
291 >                msgBox.setTextFormat(Qt::RichText);
292 >        }
293 >    msgBox.setIcon(QMessageBox::Critical);
294 >    msgBox.setText(message);
295 >    msgBox.exec();
296 > }
297 >
298 > bool showQuestion(QWidget * parent, QString message, QMessageBox::StandardButton standardButton){
299 >    return QMessageBox::question (parent, "Are you sure?", message, QMessageBox::Yes | QMessageBox::No, standardButton)==QMessageBox::Yes;
300 > }
301 >
302 > QMessageBox::StandardButton showQuestionWithCancel(QWidget * parent, QString message, QMessageBox::StandardButton standardButton){
303 >    return QMessageBox::question (parent, "Are you sure?", message, QMessageBox::Yes | QMessageBox::No | QMessageBox::Cancel, standardButton);
304 > }
305 >
306 > QStringList multipleDirSelection(const QString &title){
307 >    QFileDialog w;
308 >
309 >    // We need to use non native dialog, because native doesn't support multiple folder selection
310 >    w.setOption(QFileDialog::DontUseNativeDialog,true);
311 >
312 >    w.setFileMode(QFileDialog::DirectoryOnly);
313 >
314 >    w.setWindowTitle(title);
315 >
316 >    QTreeView *t = w.findChild<QTreeView*>();
317 >
318 >    if (t) {
319 >        t->setSelectionMode(QAbstractItemView::MultiSelection);
320 >    }
321 >
322 >    if(w.exec()){ //if accepted
323 >        return w.selectedFiles();
324 >    }
325 >    return QStringList(); //return empty
326 > }
327 >
328 > }
329 > #endif
330 >
331 > namespace Validation {
332 >
333 > // Check if any string in the list is empty
334 > bool checkEmptySpaces(QStringList toCheck){
335 >    for (const QString &current : toCheck){
336 >        if(current.trimmed().isEmpty()){
337 >            return true; //There are empty spaces
338 >        }
339 >    }
340 >    return false;
341 > }
342 >
343 > bool checkIfIntegers(QStringList toCheck){
344 >    for (const QString &current : toCheck){
345 >        if(!isStringInteger(current)){
346 >            return true; // Some aren't valid integers
347 >        }
348 >    }
349 >    return false;
350 > }
351 >
352 > bool checkIfDoubles(QStringList toCheck){
353 >    for (const QString &current : toCheck){
354 >        if(!isStringDouble(current)){
355 >            return true; // Some aren't valid doubles
356 >        }
357 >    }
358 >    return false;
359 > }
360 >
361 > bool isStringInteger(QString myString){
362 >    bool isNumber;
363 >
364 >    myString.toInt(&isNumber); //convert to int and see if it succeeds
365 >
366 >    return isNumber;
367 > }
368 >
369 > bool isStringDouble(QString myString){
370 >    bool isDouble;
371 >
372 >    myString.toDouble(&isDouble); //convert to double and see if it succeeds
373 >
374 >    return isDouble;
375 > }
376 >
377 > }
378 >
379 > namespace System {
380 >
381 > #ifdef QT_GUI_LIB
382 > // From here: http://stackoverflow.com/questions/17893328/qt-getting-the-screen-resolution-without-the-extended-monitor ty Chris
383 > QRect getScreenResolution(){
384 >    QDesktopWidget widget;
385 >    return widget.availableGeometry(widget.primaryScreen()); // or screenGeometry(), depending on your needs
386 > }
387 > #endif
388 >
389 > }
390 >
391 > #ifdef QT_GUI_LIB
392 > namespace TableWidget {
393 >
394 >
395 > void addRow(QTableWidget *myTable, QStringList &columns){
396 >    //Get actual number rows
397 >    int twSize=myTable->rowCount();
398 >
399 >    //increase the rows for the new item
400 >    myTable->setRowCount(twSize+1);
401 >
402 >    //Add to table and list to
403 >    for(int i=0; i<columns.size(); i++){
404 >        QTableWidgetItem *newColumn = new QTableWidgetItem(columns[i]);
405 >        myTable->setItem(twSize,i,newColumn);
406 >        // Add a tooltip with with the cell content
407 >        myTable->item(twSize,i)->setToolTip(myTable->item(twSize,i)->text());
408 >    }
409 >
410 > }
411 >
412 >
413 > QModelIndexList getSelectedRows(QTableWidget *myTable){
414 >    return myTable->selectionModel()->selectedRows();
415 > }
416 >
417 > QModelIndexList getCurrentRows(QTableWidget *myTable){
418 >
419 >    QModelIndexList oldSelection = getSelectedRows(myTable);
420 >
421 >    myTable->selectAll();
422 >
423 >    QModelIndexList allRows = getSelectedRows(myTable);
424 >
425 >    myTable->selectionModel()->clearSelection();
426 >
427 >    // Restore old selection
428 >    for(const QModelIndex &currentIndex : oldSelection){
429 >        myTable->selectionModel()->select(currentIndex, QItemSelectionModel::Select | QItemSelectionModel::SelectionFlag::Rows);
430 >    }
431 >
432 >    return allRows;
433 > }
434 >
435 > int getNumberSelectedRows(QTableWidget *myTable){
436 >    return getSelectedRows(myTable).size();
437 > }
438 >
439 > void clearContents(QTableWidget *myTable, const QString &nothingToClearMessage, const QString &questionToClear){
440 >
441 >    if(myTable->rowCount()==0){
442 >        Dialogs::showInfo(nothingToClearMessage);
443 >        return;
444 >    }
445 >
446 >    if(Dialogs::showQuestion(myTable, questionToClear)){
447 >        clearContentsNoPrompt(myTable);
448 >    }
449 >
450 > }
451 >
452 > void clearContentsNoPrompt(QTableWidget *myTable){
453 >    myTable->clearContents();
454 >    myTable->setRowCount(0);
455 > }
456 >
457 > // Adapted from here:
458 > // http://stackoverflow.com/questions/29176317/qtablewidget-checkbox-get-state-and-location
459 > void addCheckBox(QTableWidget *myTable, int row, int column, QCheckBox *checkbox){
460 >    if(checkbox == nullptr){
461 >        checkbox = new QCheckBox();
462 >    }
463 >
464 >    QWidget *auxLayoutWidget = new QWidget(myTable);
465 >
466 >    QHBoxLayout* checkBoxLayout = new QHBoxLayout();
467 >    checkBoxLayout->setContentsMargins(0,0,0,0);
468 >    checkBoxLayout->addWidget(checkbox);
469 >    checkBoxLayout->setAlignment(Qt::AlignCenter);
470 >    checkBoxLayout->setSpacing(0);
471 >    auxLayoutWidget->setLayout(checkBoxLayout);
472 >
473 >    myTable->setCellWidget(row, column, auxLayoutWidget);
474 > }
475 >
476 > // Adapted from here:
477 > // http://stackoverflow.com/questions/29176317/qtablewidget-checkbox-get-state-and-location
478 > QCheckBox* getCheckBoxFromCell(QTableWidget *myTable, int row, int column){
479 >    return dynamic_cast<QCheckBox*>(myTable->cellWidget(row, column)->findChild<QCheckBox *>());
480 > }
481 >
482 > // Adapted from here:
483 > // http://www.qtcentre.org/threads/3386-QTableWidget-move-row
484 > // Thanks jpn
485 > void swapRows(QTableWidget *myTable, const int indexSourceRow, const int indexDestinationRow, bool selectSwappedRow)
486 > {
487 >    // takes and returns the whole row
488 >    auto takeRow = [&myTable](int row) -> QList<QTableWidgetItem*>
489 >    {
490 >        QList<QTableWidgetItem*> rowItems;
491 >        for (int col = 0; col < myTable->columnCount(); ++col)
492 >        {
493 >            rowItems << myTable->takeItem(row, col);
494 >        }
495 >        return rowItems;
496 >    };
497 >
498 >    // sets the whole row
499 >    auto setRow = [&myTable](int row, const QList<QTableWidgetItem*>& rowItems)
500 >    {
501 >        for (int col = 0; col < myTable->columnCount(); ++col)
502 >        {
503 >            myTable->setItem(row, col, rowItems.at(col));
504 >        }
505 >    };
506 >
507 >    // take whole rows
508 >    QList<QTableWidgetItem*> sourceItems = takeRow(indexSourceRow);
509 >    QList<QTableWidgetItem*> destItems = takeRow(indexDestinationRow);
510 >
511 >    // set back in reverse order
512 >    setRow(indexSourceRow, destItems);
513 >    setRow(indexDestinationRow, sourceItems);
514 >
515 >    if(selectSwappedRow){
516 >        myTable->selectRow(indexDestinationRow);
517 >    }
518 > }
519 >
520 > void deleteSelectedRows(QTableWidget *myTable){
521 >    int size = myTable->selectionModel()->selectedRows().size();
522 >
523 >    for(int i=0; i<size; i++){
524 >        myTable->removeRow(myTable->selectionModel()->selectedRows().at(size-i-1).row());
525 >    }
526 > }
527 >
528 > }
529 > #endif
530 >
531 > #ifdef QT_GUI_LIB
532 > namespace StatusBar {
533 >
534 > void showInfo(QStatusBar * const statusBar, const QString &message){
535 >
536 >    QPalette myPalete = QPalette();
537 >    myPalete.setColor( QPalette::WindowText, QColor(0,38,255));
538 >    statusBar->setPalette( myPalete );
539 >    statusBar->showMessage(message,10000); //display by 10 seconds
540 >
541 > }
542 >
543 > void showError(QStatusBar * const statusBar, const QString &message){
544 >
545 >    QPalette myPalete = QPalette();
546 >    myPalete.setColor( QPalette::WindowText, QColor(255,0,0));
547 >    statusBar->setPalette( myPalete );
548 >    statusBar->showMessage(message,10000); //display by 10 seconds
549 >
550 > }
551 >
552 > void showSuccess(QStatusBar * const statusBar,const QString &message){
553 >
554 >    QPalette myPalete = QPalette();
555 >    myPalete.setColor( QPalette::WindowText, QColor(0,150,0));
556 >    statusBar->setPalette( myPalete );
557 >    statusBar->showMessage(message,10000); //display by 10 seconds
558 >
559 > }
560 >
561 > }
562 > #endif
563 >
564 > }
565 >
566 >
567 > /**
568 > * Copyright (c) 2017 - 2018 Fábio Bento (fabiobento512)
569 > *
570 > * Permission is hereby granted, free of charge, to any person
571 > * obtaining a copy of this software and associated documentation
572 > * files (the "Software"), to deal in the Software without
573 > * restriction, including without limitation the rights to use,
574 > * copy, modify, merge, publish, distribute, sublicense, and/or sell
575 > * copies of the Software, and to permit persons to whom the
576 > * Software is furnished to do so, subject to the following
577 > * conditions:
578 > *
579 > * The above copyright notice and this permission notice shall be
580 > * included in all copies or substantial portions of the Software.
581 > *
582 > * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
583 > * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
584 > * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
585 > * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
586 > * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
587 > * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
588 > * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
589 > * OTHER DEALINGS IN THE SOFTWARE.
590 > */

Diff Legend

Removed lines
+ Added lines
< Changed lines (old)
> Changed lines (new)