ViewVC Help
View File | Revision Log | View Changeset | Root Listing
root/Oni2/s10k/CommonUtils/util.cpp
Revision: 1109
Committed: Sat Feb 16 17:23:09 2019 UTC (6 years, 7 months ago) by s10k
Content type: text/x-c++src
File size: 17065 byte(s)
Log Message:
small dialogs functions changes, now they have an optional value to set as rich text

File Contents

# Content
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 */