├── LICENSE ├── MaterialDark.qss ├── QNote.pro ├── README.md ├── _config.yml ├── customtabwidget.cpp ├── customtabwidget.h ├── customtextedit.cpp ├── customtextedit.h ├── downloadmanager.cpp ├── downloadmanager.h ├── img ├── img.qrc ├── note.ico ├── note.png ├── reloading.gif └── unsaved.png ├── main.cpp ├── mainwindow.cpp ├── mainwindow.h ├── mainwindow.ui ├── searchdialog.cpp ├── searchdialog.h ├── searchdialog.ui ├── tabwidget.h ├── worker.cpp └── worker.h /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Jaime Quiroga 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /MaterialDark.qss: -------------------------------------------------------------------------------- 1 | /* 2 | Material Dark Style Sheet for QT Applications 3 | Author: Jaime A. Quiroga P. 4 | Inspired on https://github.com/jxfwinter/qt-material-stylesheet 5 | Company: GTRONICK 6 | Last updated: 09/05/2018, 17:47. 7 | Available at: https://github.com/GTRONICK/QSS/blob/master/MaterialDark.qss 8 | */ 9 | QMainWindow { 10 | background-color:#1e1d23; 11 | } 12 | QDialog { 13 | background-color:#1e1d23; 14 | } 15 | QColorDialog { 16 | background-color:#1e1d23; 17 | } 18 | QTextEdit { 19 | background-color:#1e1d23; 20 | color: #a9b7c6; 21 | } 22 | QPlainTextEdit { 23 | selection-background-color:#007b50; 24 | background-color:#1e1d23; 25 | border-style: solid; 26 | border-top-color: transparent; 27 | border-right-color: transparent; 28 | border-left-color: transparent; 29 | border-bottom-color: transparent; 30 | border-width: 1px; 31 | color: #a9b7c6; 32 | } 33 | QPushButton{ 34 | border-style: solid; 35 | border-top-color: transparent; 36 | border-right-color: transparent; 37 | border-left-color: transparent; 38 | border-bottom-color: transparent; 39 | border-width: 1px; 40 | border-style: solid; 41 | color: #a9b7c6; 42 | padding: 2px; 43 | background-color: #1e1d23; 44 | } 45 | QPushButton::default{ 46 | border-style: inset; 47 | border-top-color: transparent; 48 | border-right-color: transparent; 49 | border-left-color: transparent; 50 | border-bottom-color: #04b97f; 51 | border-width: 1px; 52 | color: #a9b7c6; 53 | padding: 2px; 54 | background-color: #1e1d23; 55 | } 56 | QToolButton { 57 | border-style: solid; 58 | border-top-color: transparent; 59 | border-right-color: transparent; 60 | border-left-color: transparent; 61 | border-bottom-color: #04b97f; 62 | border-bottom-width: 1px; 63 | border-style: solid; 64 | color: #a9b7c6; 65 | padding: 2px; 66 | background-color: #1e1d23; 67 | } 68 | QToolButton:hover{ 69 | border-style: solid; 70 | border-top-color: transparent; 71 | border-right-color: transparent; 72 | border-left-color: transparent; 73 | border-bottom-color: #37efba; 74 | border-bottom-width: 2px; 75 | border-bottom-radius: 6px; 76 | border-style: solid; 77 | color: #FFFFFF; 78 | padding-bottom: 1px; 79 | background-color: #1e1d23; 80 | } 81 | QPushButton:hover{ 82 | border-style: solid; 83 | border-top-color: transparent; 84 | border-right-color: transparent; 85 | border-left-color: transparent; 86 | border-bottom-color: #37efba; 87 | border-bottom-width: 1px; 88 | border-bottom-radius: 6px; 89 | border-style: solid; 90 | color: #FFFFFF; 91 | padding-bottom: 2px; 92 | background-color: #1e1d23; 93 | } 94 | QPushButton:pressed{ 95 | border-style: solid; 96 | border-top-color: transparent; 97 | border-right-color: transparent; 98 | border-left-color: transparent; 99 | border-bottom-color: #37efba; 100 | border-bottom-width: 2px; 101 | border-bottom-radius: 6px; 102 | border-style: solid; 103 | color: #37efba; 104 | padding-bottom: 1px; 105 | background-color: #1e1d23; 106 | } 107 | QPushButton:disabled{ 108 | border-style: solid; 109 | border-top-color: transparent; 110 | border-right-color: transparent; 111 | border-left-color: transparent; 112 | border-bottom-color: #808086; 113 | border-bottom-width: 2px; 114 | border-bottom-radius: 6px; 115 | border-style: solid; 116 | color: #808086; 117 | padding-bottom: 1px; 118 | background-color: #1e1d23; 119 | } 120 | QLineEdit { 121 | border-width: 1px; border-radius: 4px; 122 | border-color: rgb(58, 58, 58); 123 | border-style: inset; 124 | padding: 0 8px; 125 | color: #a9b7c6; 126 | background:#1e1d23; 127 | selection-background-color:#007b50; 128 | selection-color: #FFFFFF; 129 | } 130 | QLabel { 131 | color: #a9b7c6; 132 | } 133 | QLCDNumber { 134 | color: #37e6b4; 135 | } 136 | QProgressBar { 137 | text-align: center; 138 | color: rgb(240, 240, 240); 139 | border-width: 1px; 140 | border-radius: 10px; 141 | border-color: rgb(58, 58, 58); 142 | border-style: inset; 143 | background-color:#1e1d23; 144 | } 145 | QProgressBar::chunk { 146 | background-color: #04b97f; 147 | border-radius: 5px; 148 | } 149 | QMenuBar { 150 | background-color: #1e1d23; 151 | } 152 | QMenuBar::item { 153 | color: #a9b7c6; 154 | spacing: 3px; 155 | padding: 1px 4px; 156 | background: #1e1d23; 157 | } 158 | 159 | QMenuBar::item:selected { 160 | background:#1e1d23; 161 | color: #FFFFFF; 162 | } 163 | QMenu::item:selected { 164 | border-style: solid; 165 | border-top-color: transparent; 166 | border-right-color: transparent; 167 | border-left-color: #04b97f; 168 | border-bottom-color: transparent; 169 | border-left-width: 2px; 170 | color: #FFFFFF; 171 | padding-left:15px; 172 | padding-top:4px; 173 | padding-bottom:4px; 174 | padding-right:7px; 175 | background-color: #1e1d23; 176 | } 177 | QMenu::item { 178 | border-style: solid; 179 | border-top-color: transparent; 180 | border-right-color: transparent; 181 | border-left-color: transparent; 182 | border-bottom-color: transparent; 183 | border-bottom-width: 1px; 184 | border-style: solid; 185 | color: #a9b7c6; 186 | padding-left:17px; 187 | padding-top:4px; 188 | padding-bottom:4px; 189 | padding-right:7px; 190 | background-color: #1e1d23; 191 | } 192 | QMenu{ 193 | background-color:#1e1d23; 194 | } 195 | QTabWidget { 196 | color:rgb(0,0,0); 197 | background-color:#1e1d23; 198 | } 199 | QTabWidget::pane { 200 | border-color: rgb(77,77,77); 201 | background-color:#1e1d23; 202 | border-style: solid; 203 | border-width: 1px; 204 | border-radius: 6px; 205 | } 206 | QTabBar::tab { 207 | border-style: solid; 208 | border-top-color: transparent; 209 | border-right-color: transparent; 210 | border-left-color: transparent; 211 | border-bottom-color: transparent; 212 | border-bottom-width: 1px; 213 | border-style: solid; 214 | color: #808086; 215 | padding: 3px; 216 | margin-left:3px; 217 | background-color: #1e1d23; 218 | } 219 | QTabBar::tab:selected, QTabBar::tab:last:selected, QTabBar::tab:hover { 220 | border-style: solid; 221 | border-top-color: transparent; 222 | border-right-color: transparent; 223 | border-left-color: transparent; 224 | border-bottom-color: #04b97f; 225 | border-bottom-width: 2px; 226 | border-style: solid; 227 | color: #FFFFFF; 228 | padding-left: 3px; 229 | padding-bottom: 2px; 230 | margin-left:3px; 231 | background-color: #1e1d23; 232 | } 233 | 234 | QCheckBox { 235 | color: #a9b7c6; 236 | padding: 2px; 237 | } 238 | QCheckBox:disabled { 239 | color: #808086; 240 | padding: 2px; 241 | } 242 | 243 | QCheckBox:hover { 244 | border-radius:4px; 245 | border-style:solid; 246 | padding-left: 1px; 247 | padding-right: 1px; 248 | padding-bottom: 1px; 249 | padding-top: 1px; 250 | border-width:1px; 251 | border-color: rgb(87, 97, 106); 252 | background-color:#1e1d23; 253 | } 254 | QCheckBox::indicator:checked { 255 | 256 | height: 10px; 257 | width: 10px; 258 | border-style:solid; 259 | border-width: 1px; 260 | border-color: #04b97f; 261 | color: #a9b7c6; 262 | background-color: #04b97f; 263 | } 264 | QCheckBox::indicator:unchecked { 265 | 266 | height: 10px; 267 | width: 10px; 268 | border-style:solid; 269 | border-width: 1px; 270 | border-color: #04b97f; 271 | color: #a9b7c6; 272 | background-color: transparent; 273 | } 274 | QRadioButton { 275 | color: #a9b7c6; 276 | background-color: #1e1d23; 277 | padding: 1px; 278 | } 279 | QRadioButton::indicator:checked { 280 | height: 10px; 281 | width: 10px; 282 | border-style:solid; 283 | border-radius:5px; 284 | border-width: 1px; 285 | border-color: #04b97f; 286 | color: #a9b7c6; 287 | background-color: #04b97f; 288 | } 289 | QRadioButton::indicator:!checked { 290 | height: 10px; 291 | width: 10px; 292 | border-style:solid; 293 | border-radius:5px; 294 | border-width: 1px; 295 | border-color: #04b97f; 296 | color: #a9b7c6; 297 | background-color: transparent; 298 | } 299 | QStatusBar { 300 | color:#027f7f; 301 | } 302 | QSpinBox { 303 | color: #a9b7c6; 304 | background-color: #1e1d23; 305 | } 306 | QDoubleSpinBox { 307 | color: #a9b7c6; 308 | background-color: #1e1d23; 309 | } 310 | QTimeEdit { 311 | color: #a9b7c6; 312 | background-color: #1e1d23; 313 | } 314 | QDateTimeEdit { 315 | color: #a9b7c6; 316 | background-color: #1e1d23; 317 | } 318 | QDateEdit { 319 | color: #a9b7c6; 320 | background-color: #1e1d23; 321 | } 322 | QComboBox { 323 | color: #a9b7c6; 324 | background: #1e1d23; 325 | } 326 | QComboBox:editable { 327 | background: #1e1d23; 328 | color: #a9b7c6; 329 | selection-background-color: #1e1d23; 330 | } 331 | QComboBox QAbstractItemView { 332 | color: #a9b7c6; 333 | background: #1e1d23; 334 | selection-color: #FFFFFF; 335 | selection-background-color: #1e1d23; 336 | } 337 | QComboBox:!editable:on, QComboBox::drop-down:editable:on { 338 | color: #a9b7c6; 339 | background: #1e1d23; 340 | } 341 | QFontComboBox { 342 | color: #a9b7c6; 343 | background-color: #1e1d23; 344 | } 345 | QToolBox { 346 | color: #a9b7c6; 347 | background-color: #1e1d23; 348 | } 349 | QToolBox::tab { 350 | color: #a9b7c6; 351 | background-color: #1e1d23; 352 | } 353 | QToolBox::tab:selected { 354 | color: #FFFFFF; 355 | background-color: #1e1d23; 356 | } 357 | QScrollArea { 358 | color: #FFFFFF; 359 | background-color: #1e1d23; 360 | } 361 | QSlider::groove:horizontal { 362 | height: 5px; 363 | background: #04b97f; 364 | } 365 | QSlider::groove:vertical { 366 | width: 5px; 367 | background: #04b97f; 368 | } 369 | QSlider::handle:horizontal { 370 | background: qlineargradient(x1:0, y1:0, x2:1, y2:1, stop:0 #b4b4b4, stop:1 #8f8f8f); 371 | border: 1px solid #5c5c5c; 372 | width: 14px; 373 | margin: -5px 0; 374 | border-radius: 7px; 375 | } 376 | QSlider::handle:vertical { 377 | background: qlineargradient(x1:1, y1:1, x2:0, y2:0, stop:0 #b4b4b4, stop:1 #8f8f8f); 378 | border: 1px solid #5c5c5c; 379 | height: 14px; 380 | margin: 0 -5px; 381 | border-radius: 7px; 382 | } 383 | QSlider::add-page:horizontal { 384 | background: white; 385 | } 386 | QSlider::add-page:vertical { 387 | background: white; 388 | } 389 | QSlider::sub-page:horizontal { 390 | background: #04b97f; 391 | } 392 | QSlider::sub-page:vertical { 393 | background: #04b97f; 394 | } 395 | -------------------------------------------------------------------------------- /QNote.pro: -------------------------------------------------------------------------------- 1 | #------------------------------------------------- 2 | # 3 | # Project created by QtCreator 2017-04-05T08:07:51 4 | # 5 | #------------------------------------------------- 6 | 7 | QT += core gui network 8 | 9 | greaterThan(QT_MAJOR_VERSION, 4): QT += widgets 10 | 11 | TARGET = QNote 12 | TEMPLATE = app 13 | 14 | # The following define makes your compiler emit warnings if you use 15 | # any feature of Qt which as been marked as deprecated (the exact warnings 16 | # depend on your compiler). Please consult the documentation of the 17 | # deprecated API in order to know how to port your code away from it. 18 | DEFINES += QT_DEPRECATED_WARNINGS 19 | 20 | # You can also make your code fail to compile if you use deprecated APIs. 21 | # In order to do so, uncomment the following line. 22 | # You can also select to disable deprecated APIs only up to a certain version of Qt. 23 | #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 24 | 25 | 26 | SOURCES += main.cpp\ 27 | mainwindow.cpp \ 28 | customtabwidget.cpp \ 29 | searchdialog.cpp \ 30 | worker.cpp \ 31 | customtextedit.cpp \ 32 | downloadmanager.cpp 33 | 34 | HEADERS += mainwindow.h \ 35 | customtabwidget.h \ 36 | searchdialog.h \ 37 | worker.h \ 38 | customtextedit.h \ 39 | downloadmanager.h 40 | 41 | FORMS += mainwindow.ui \ 42 | searchdialog.ui 43 | 44 | RESOURCES += \ 45 | img/img.qrc 46 | 47 | win32:RC_ICONS += img/note.ico 48 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # QNote 2 | Lightweight yet powerful and fast QT Text editor 3 | 4 | ![QNote_GUI](https://github.com/user-attachments/assets/93c5d9a2-ec8c-4866-948a-311a0d63ea6b) 5 | 6 | *Preview in Plasma Desktop* 7 | 8 | # HOW TO INSTALL: 9 | 10 | **Windows:** 11 | Download from here: ![https://github.com/GTRONICK/QNote/releases/download/v1.7.5/QNote_Windows.zip](https://github.com/GTRONICK/QNote/releases/download/v1.7.5/QNote_Windows.zip) 12 | 13 | Just decompress the zip file and run QNote.exe or, if you have a previous QNote version, just download the QNote.exe file and replace the existing one. 14 | 15 | **Linux:** 16 | Download from here: ![https://github.com/GTRONICK/QNote/releases/download/v1.7.5/QNote_Linux.zip](https://github.com/GTRONICK/QNote/releases/download/v1.7.5/QNote_Linux.zip) 17 | 18 | Just decompress the zip file and run 19 | 20 | sh QNote.sh 21 | 22 | # HOW TO BUILD FROM SOURCE: 23 | 24 | It is strongly recommended to use QtCreator with Qt5.11.2 to compile QNote, otherwise you may experiment unexpected behavior. However, you can build it manually with: 25 | 26 | qmake QNote.pro 27 | make all -j4 28 | make clean 29 | 30 | # HOW TO USE: 31 | 32 | **1. Open new document:** 33 | Go to the File menu, then click on Open File... 34 | 35 | **2. Save a file:** 36 | Press Ctrl + S, or go to the File menu, then click on Save File. If the file has not been saved before, the "save as" dialog will appear. 37 | 38 | **3. Save a File with a new name:** 39 | Press Ctrl + Shift + S, or go to the File menu, then click on Save As. 40 | 41 | **4. Open a new tab to edit a new or existing file:** 42 | Press Ctrl + T or go to the File menu, and Click on New Tab. 43 | 44 | **5. Close a Tab:** 45 | Press Ctrl + W to close the current Tab, or press the close button in the desired tab. 46 | 47 | **6. Reload a File:** 48 | To reload the current file, press F5, or go to the Tools menu and click on Reload File. 49 | 50 | **7. Auto Reload the current File:** 51 | If you want to reload the current file automatically after some delay in milliseconds, pres F6, or go to the Tools menu, and select Auto Reload. This will clear the current text but not the file. 52 | 53 | **8. To Search or replace text:** 54 | Press Ctrl + F, or go to the Tools menu and click on Find & Replace. 55 | 56 | **9. To navigate to a specific line:** 57 | Press Ctrl + G, or go to the Tools menu, and click on Go to Line... Then, type the line you want to go to. 58 | 59 | **10. Activate the Word Wrap:** (Active by default) 60 | Press Alt + W or go to the Settings menu, and check Word Wrap. This will hide the horizontal scrollbar and will wrap the text if it exceeds the horizontal page limit. 61 | 62 | **11. Load a Theme:** 63 | You can load a Style Sheet for this application and make it look as cool as you want!, just go to the Settings menu, and click on Load Theme. Then select a valid Style Sheet. 64 | Go to https://github.com/GTRONICK/QSS for some cool themes!. 65 | 66 | **12. Revert to the system theme:** 67 | Go to the Settings menu and click on System Theme, to revert to the default theme. 68 | 69 | **13. Set the default reload delay:** 70 | You can adjust the reload delay, to make the file reload faster, or slower. Just go to the Settings menu, and click on Auto Reload Delay. Then, specify the desired Delay, and press OK. The 71 | minimum value is 20 ms. 72 | 73 | **14. Adjust the text Font:** 74 | Go to the Settings menu, and click on Font. The font dialog will appear, and the new font can now be selected. This will remain until you change it again. 75 | 76 | **15. Set the application Always on Top:** 77 | Go to the Settings menu and check the Always on Top check box. This change will apply immediately. This could not work as spected in Windows, for now. 78 | 79 | **16. Erase And Save:** 80 | Press F8 or go to Tools -> Erase And Save. This will delete the file contents and save it as an empty file. 81 | 82 | **17. Erase, save and Auto Reload:** 83 | Press F7, or go to Tools -> Erase, save and Auto Reload. This will delete the file contents, and activate the auto reload feature. 84 | 85 | ## ADVANCED USAGE: 86 | 87 | **16. Group control:** 88 | This feature allow you to assign up to 4 buffers to hold text. Press Ctrl + <1-4> to assign the desired group, for example: 89 | 90 | Ctrl +1, will assign the current selected text, to the buffer 1; If no text is selected, the buffer will be cleared. 91 | 92 | To paste a buffer content at the current cursor position or selection, press F <1-4>. 93 | 94 | Think in this as a multi-clipboard. 95 | 96 | **17. Open the file's containing folder:** 97 | Click on the status bar, at the file path location to open the containing folder, or press F9. 98 | 99 | ## IN THIS VERSION: 100 | 101 | 1. General bug fixes. 102 | 103 | QNote is now compiled with QT5.11. 104 | 105 | ## HOW TO CONTRIBUTE: 106 | 107 | Create a new issue if you find some bug, or have any suggestion. 108 | -------------------------------------------------------------------------------- /_config.yml: -------------------------------------------------------------------------------- 1 | theme: jekyll-theme-cayman 2 | show_downloads: true 3 | -------------------------------------------------------------------------------- /customtabwidget.cpp: -------------------------------------------------------------------------------- 1 | #include "customtabwidget.h" 2 | #include 3 | #include 4 | #include 5 | 6 | CustomTabWidget::CustomTabWidget(QWidget *parent):QTabWidget(parent) 7 | { 8 | connect(this->tabBar(),SIGNAL(tabMoved(int,int)),this,SLOT(ctw_slot_reorderTabs(int,int))); 9 | } 10 | 11 | void CustomTabWidget::ctw_slot_reorderTabs(int from, int to) 12 | { 13 | emit(ctw_signal_tabMoved(from, to)); 14 | } 15 | -------------------------------------------------------------------------------- /customtabwidget.h: -------------------------------------------------------------------------------- 1 | #ifndef CUSTOMTABWIDGET_H 2 | #define CUSTOMTABWIDGET_H 3 | #include 4 | 5 | class CustomTabWidget : public QTabWidget 6 | { 7 | Q_OBJECT 8 | public: 9 | CustomTabWidget(QWidget *parent); 10 | 11 | public slots: 12 | void ctw_slot_reorderTabs(int from, int to); 13 | 14 | signals: 15 | void ctw_signal_tabMoved(int from, int to); 16 | }; 17 | 18 | #endif // CUSTOMTABWIDGET_H 19 | -------------------------------------------------------------------------------- /customtextedit.cpp: -------------------------------------------------------------------------------- 1 | #include "customtextedit.h" 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | CustomTextEdit::CustomTextEdit() 10 | { 11 | connect(this, SIGNAL(cursorPositionChanged()), this, SLOT(highlightCurrentLine())); 12 | giFlag = 1; 13 | } 14 | 15 | void CustomTextEdit::dragEnterEvent(QDragEnterEvent *event) 16 | { 17 | event->acceptProposedAction(); 18 | } 19 | 20 | void CustomTextEdit::dropEvent(QDropEvent *event) 21 | { 22 | emit this->customTextEdit_signal_processDropEvent(event); 23 | } 24 | 25 | void CustomTextEdit::dragMoveEvent(QDragMoveEvent *event) 26 | { 27 | event->acceptProposedAction(); 28 | } 29 | 30 | void CustomTextEdit::highlightCurrentLine() 31 | { 32 | if(giFlag == 1){ 33 | QList extraSelections = this->extraSelections(); 34 | 35 | if(extraSelections.count() > 0){ 36 | extraSelections.removeLast(); 37 | } 38 | 39 | QTextEdit::ExtraSelection selection; 40 | 41 | QColor lineColor = QColor(this->palette().background().color().darker(110)); 42 | 43 | selection.format.setBackground(lineColor); 44 | selection.format.setProperty(QTextFormat::FullWidthSelection, true); 45 | selection.cursor = textCursor(); 46 | selection.cursor.clearSelection(); 47 | extraSelections.append(selection); 48 | setExtraSelections(extraSelections); 49 | } 50 | } 51 | 52 | void CustomTextEdit::cte_slot_disableHighLight() 53 | { 54 | giFlag = 0; 55 | } 56 | 57 | void CustomTextEdit::cte_slot_enableHighLight() 58 | { 59 | giFlag = 1; 60 | } 61 | 62 | void CustomTextEdit::keyPressEvent(QKeyEvent *e){ 63 | 64 | QTextCursor cursor = this->textCursor(); 65 | 66 | if(e->key() == Qt::Key_Tab && cursor.hasSelection()){ 67 | 68 | cursor.beginEditBlock(); 69 | int start = cursor.selectionStart(); 70 | int end = cursor.selectionEnd(); 71 | 72 | cursor.setPosition(end, QTextCursor::KeepAnchor); 73 | QTextBlock endBlock = cursor.block(); 74 | 75 | cursor.setPosition(start, QTextCursor::KeepAnchor); 76 | QTextBlock block = cursor.block(); 77 | 78 | for(; block.isValid() && !(endBlock < block); block = block.next()) 79 | { 80 | if (!block.isValid()) 81 | continue; 82 | 83 | cursor.movePosition(QTextCursor::StartOfLine); 84 | cursor.clearSelection(); 85 | cursor.insertText("\t"); 86 | cursor.movePosition(QTextCursor::NextBlock); 87 | } 88 | 89 | cursor.endEditBlock(); 90 | 91 | } else if(e->key() == Qt::Key_Backtab){ 92 | 93 | cursor.beginEditBlock(); 94 | 95 | int start = cursor.selectionStart(); 96 | int end = cursor.selectionEnd(); 97 | 98 | cursor.setPosition(end, QTextCursor::KeepAnchor); 99 | QTextBlock endBlock = cursor.block(); 100 | 101 | cursor.setPosition(start, QTextCursor::KeepAnchor); 102 | QTextBlock block = cursor.block(); 103 | 104 | for(; block.isValid() && !(endBlock < block); block = block.next()) 105 | { 106 | if (!block.isValid()) 107 | continue; 108 | 109 | cursor.setPosition(block.position() + 1, QTextCursor::KeepAnchor); 110 | cursor.clearSelection(); 111 | if(block.text().startsWith("\t") || block.text().startsWith(" ")) cursor.deletePreviousChar(); 112 | } 113 | 114 | cursor.endEditBlock(); 115 | 116 | } else if(e->key() == Qt::Key_Return || e->key() == Qt::Key_Enter) { 117 | 118 | QTextBlock block = cursor.block(); 119 | int liTabCount = 0; 120 | int liSpaceCount = 0; 121 | QString lsText = block.text(); 122 | QString::iterator i; 123 | 124 | for(i = lsText.begin(); i != lsText.end(); ++i) { 125 | if(*i == '\t') { 126 | liTabCount ++; 127 | } else if (*i == ' ') { 128 | liSpaceCount ++; 129 | } 130 | else break; 131 | } 132 | 133 | this->insertPlainText("\r\n"); 134 | 135 | if(block.text().startsWith(" ")) { 136 | this->insertSpaces(liSpaceCount); 137 | this->insertTabs(liTabCount); 138 | } else if(block.text().startsWith("\t")) { 139 | this->insertTabs(liTabCount); 140 | this->insertSpaces(liSpaceCount); 141 | } else { 142 | this->setTextCursor(cursor); 143 | } 144 | }else { 145 | QPlainTextEdit::keyPressEvent(e); 146 | } 147 | } 148 | 149 | void CustomTextEdit::insertTabs(int liTabCount) 150 | { 151 | for(int i = 0; i < liTabCount; i ++) { 152 | this->insertPlainText("\t"); 153 | } 154 | } 155 | 156 | void CustomTextEdit::insertSpaces(int liSpaceCount) 157 | { 158 | for(int i = 0; i < liSpaceCount; i ++) { 159 | this->insertPlainText(" "); 160 | } 161 | } 162 | -------------------------------------------------------------------------------- /customtextedit.h: -------------------------------------------------------------------------------- 1 | #ifndef CUSTOMTEXTEDIT_H 2 | #define CUSTOMTEXTEDIT_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | class CustomTextEdit : public QPlainTextEdit 11 | { 12 | Q_OBJECT 13 | public: 14 | CustomTextEdit(); 15 | void dragEnterEvent(QDragEnterEvent *event); 16 | void dropEvent(QDropEvent *event); 17 | void dragMoveEvent(QDragMoveEvent *event); 18 | void keyPressEvent(QKeyEvent *e); 19 | void insertTabs(int liTabCount); 20 | void insertSpaces(int liSpaceCount); 21 | 22 | public slots: 23 | void highlightCurrentLine(); 24 | void cte_slot_disableHighLight(); 25 | void cte_slot_enableHighLight(); 26 | 27 | signals: 28 | void customTextEdit_signal_processDropEvent(QDropEvent *event); 29 | 30 | private: 31 | int giFlag; 32 | }; 33 | 34 | #endif // CUSTOMTEXTEDIT_H 35 | -------------------------------------------------------------------------------- /downloadmanager.cpp: -------------------------------------------------------------------------------- 1 | #include "downloadmanager.h" 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | DownloadManager::DownloadManager(QObject *parent) : QObject(parent) 8 | { 9 | connect(&manager, SIGNAL(finished(QNetworkReply*)),SLOT(downloadFinished(QNetworkReply*))); 10 | } 11 | 12 | void DownloadManager::doDownload(const QUrl &url) 13 | { 14 | QNetworkRequest request(url); 15 | request.setRawHeader("User-Agent", "Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.8.1.12) Gecko/20080214 Firefox/2.0.0.12"); 16 | QNetworkReply *reply = manager.get(request); 17 | 18 | #if QT_CONFIG(ssl) 19 | connect(reply, SIGNAL(sslErrors(QList)),this,SLOT(sslErrors(QList))); 20 | #endif 21 | 22 | } 23 | 24 | QString DownloadManager::saveFileName(const QUrl &url) 25 | { 26 | QString path = url.path(); 27 | QString basename = QFileInfo(path).fileName(); 28 | 29 | return basename; 30 | } 31 | 32 | bool DownloadManager::saveToDisk(const QString &filename, QIODevice *data) 33 | { 34 | QFile file(filename); 35 | if (!file.open(QIODevice::WriteOnly)) { 36 | qDebug() << "Could not open %s for writing: %s\n" << qPrintable(filename) << qPrintable(file.errorString()); 37 | return false; 38 | } 39 | 40 | file.write(data->readAll()); 41 | file.close(); 42 | 43 | return true; 44 | } 45 | 46 | bool DownloadManager::isHttpRedirect(QNetworkReply *reply) 47 | { 48 | int statusCode = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(); 49 | return statusCode == 301 || statusCode == 302 || statusCode == 303 50 | || statusCode == 305 || statusCode == 307 || statusCode == 308; 51 | } 52 | 53 | void DownloadManager::execute(QString lsLink) 54 | { 55 | QUrl url = QUrl::fromEncoded(lsLink.toLocal8Bit()); 56 | doDownload(url); 57 | } 58 | 59 | void DownloadManager::sslErrors(const QList &sslErrors) 60 | { 61 | #if QT_CONFIG(ssl) 62 | for (const QSslError &error : sslErrors) 63 | qDebug() << "SSL error: %s\n" << qPrintable(error.errorString()); 64 | #else 65 | Q_UNUSED(sslErrors); 66 | #endif 67 | } 68 | 69 | void DownloadManager::downloadFinished(QNetworkReply *reply) 70 | { 71 | QUrl url = reply->url(); 72 | if (reply->error()) { 73 | qDebug() << "Failed" << " " << reply->errorString(); 74 | } else { 75 | if (isHttpRedirect(reply)) { 76 | qDebug() << "Redirected"; 77 | } else { 78 | QString filename = saveFileName(url); 79 | if (saveToDisk(filename, reply)) { 80 | qDebug() << "File downloaded"; 81 | } 82 | } 83 | } 84 | 85 | reply->deleteLater(); 86 | } 87 | -------------------------------------------------------------------------------- /downloadmanager.h: -------------------------------------------------------------------------------- 1 | #ifndef DOWNLOADMANAGER_H 2 | #define DOWNLOADMANAGER_H 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | class DownloadManager : public QObject 9 | { 10 | Q_OBJECT 11 | QNetworkAccessManager manager; 12 | 13 | public: 14 | explicit DownloadManager(QObject *parent = nullptr); 15 | static QString saveFileName(const QUrl &url); 16 | static bool isHttpRedirect(QNetworkReply *reply); 17 | bool saveToDisk(const QString &filename, QIODevice *data); 18 | void doDownload(const QUrl &url); 19 | 20 | 21 | signals: 22 | 23 | public slots: 24 | void execute(QString lsLink); 25 | void downloadFinished(QNetworkReply *reply); 26 | void sslErrors(const QList &errors); 27 | }; 28 | 29 | #endif // DOWNLOADMANAGER_H 30 | -------------------------------------------------------------------------------- /img/img.qrc: -------------------------------------------------------------------------------- 1 | 2 | 3 | note.png 4 | reloading.gif 5 | unsaved.png 6 | 7 | 8 | -------------------------------------------------------------------------------- /img/note.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GTRONICK/QNote/dc9bb2e172f52485c9c4749779593a0c0c14c490/img/note.ico -------------------------------------------------------------------------------- /img/note.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GTRONICK/QNote/dc9bb2e172f52485c9c4749779593a0c0c14c490/img/note.png -------------------------------------------------------------------------------- /img/reloading.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GTRONICK/QNote/dc9bb2e172f52485c9c4749779593a0c0c14c490/img/reloading.gif -------------------------------------------------------------------------------- /img/unsaved.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GTRONICK/QNote/dc9bb2e172f52485c9c4749779593a0c0c14c490/img/unsaved.png -------------------------------------------------------------------------------- /main.cpp: -------------------------------------------------------------------------------- 1 | #include "mainwindow.h" 2 | #include 3 | #include 4 | 5 | int main(int argc, char *argv[]) 6 | { 7 | QApplication a(argc, argv); 8 | MainWindow w; 9 | w.show(); 10 | 11 | if(argc >= 2){ 12 | QStringList lobFilenames = QApplication::arguments(); 13 | lobFilenames.removeFirst(); 14 | w.setFileNameFromCommandLine(lobFilenames); 15 | } 16 | 17 | return a.exec(); 18 | } 19 | -------------------------------------------------------------------------------- /mainwindow.cpp: -------------------------------------------------------------------------------- 1 | #include "customtabwidget.h" 2 | #include "customtextedit.h" 3 | #include "ui_mainwindow.h" 4 | #include "mainwindow.h" 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | 26 | MainWindow::MainWindow(QWidget *parent) : 27 | QMainWindow(parent), 28 | ui(new Ui::MainWindow) 29 | { 30 | ui->setupUi(this); 31 | 32 | gbIsAutoreloadEnabled = false; 33 | gbIsOpenedFile = false; 34 | gbIsReloadFile = false; 35 | gbSaveCancelled = false; 36 | gbShowEraseAndSaveMessageBox = true; 37 | giCurrentFileIndex = 0; 38 | giCurrentTabIndex = 0; 39 | giDefaultDirCounter = 0; 40 | giOpenWithFlag = 0; 41 | giTimerDelay = 20; 42 | giTotalTabs = 0; 43 | gobFileNames.clear(); 44 | gobRecentFiles.clear(); 45 | gobMovie = new QMovie("://reloading.gif"); 46 | gobMovie->setScaledSize(QSize(15,15)); 47 | gobSearchDialog = new SearchDialog(this); 48 | gobTimer = new QTimer(this); 49 | gsDefaultDir = QDir::homePath(); 50 | gsThemeFile = "Default"; 51 | gsStatusBarColor = "orange"; 52 | worker = new Worker; 53 | workerThread = new QThread; 54 | setAcceptDrops(true); 55 | loadConfig(); 56 | 57 | QShortcut *menuBar_shortcut = new QShortcut(QKeySequence(tr("Ctrl+M")),this); 58 | QShortcut *gr1_shortcut = new QShortcut(QKeySequence(tr("Ctrl+1")),this); 59 | QShortcut *gr2_shortcut = new QShortcut(QKeySequence(tr("Ctrl+2")),this); 60 | QShortcut *gr3_shortcut = new QShortcut(QKeySequence(tr("Ctrl+3")),this); 61 | QShortcut *gr4_shortcut = new QShortcut(QKeySequence(tr("Ctrl+4")),this); 62 | QShortcut *paste_gr1_shortcut = new QShortcut(QKeySequence(tr("F1")),this); 63 | QShortcut *paste_gr2_shortcut = new QShortcut(QKeySequence(tr("F2")),this); 64 | QShortcut *paste_gr3_shortcut = new QShortcut(QKeySequence(tr("F3")),this); 65 | QShortcut *paste_gr4_shortcut = new QShortcut(QKeySequence(tr("F4")),this); 66 | QShortcut *openFileLocation_shortCut = new QShortcut(QKeySequence(tr("F9")),this); 67 | 68 | connect(ui->tabWidget,SIGNAL(currentChanged(int)),this,SLOT(main_slot_tabChanged(int))); 69 | connect(ui->tabWidget,SIGNAL(ctw_signal_tabMoved(int,int)),this,SLOT(main_slot_tabMoved(int,int))); 70 | connect(ui->menuOpen_Recent, SIGNAL(triggered(QAction*)), this, SLOT(main_slot_loadFileFromAction(QAction*))); 71 | connect(this,SIGNAL(main_signal_setTextEdit(QPlainTextEdit*)),gobSearchDialog,SLOT(search_slot_setTextEdit(QPlainTextEdit*))); 72 | connect(gobSearchDialog,SIGNAL(search_signal_getTextEditText()),this,SLOT(main_slot_getTextEditText())); 73 | connect(gobSearchDialog,SIGNAL(search_signal_resetCursor()),this,SLOT(main_slot_resetCursor())); 74 | connect(this,SIGNAL(main_signal_loadFile(QFile*)),worker,SLOT(worker_slot_loadFile(QFile*))); 75 | connect(worker,SIGNAL(worker_signal_appendText(QString)),this,SLOT(main_slot_appendText(QString))); 76 | connect(worker,SIGNAL(worker_signal_insertText(QString)),this,SLOT(main_slot_insertText(QString))); 77 | connect(gobTimer, SIGNAL(timeout()), this, SLOT(main_slot_tailFile())); 78 | connect(menuBar_shortcut,SIGNAL(activated()),this,SLOT(main_slot_showHideMenuBar())); 79 | connect(this,SIGNAL(main_signal_tailFile(QFile*)),worker,SLOT(worker_slot_tailFile(QFile*))); 80 | connect(this,SIGNAL(main_signal_setCurrentFileSize(int)),worker,SLOT(worker_slot_setCurrentFileSize(int))); 81 | 82 | connect(gr1_shortcut,SIGNAL(activated()),this,SLOT(main_slot_gr1())); 83 | connect(gr2_shortcut,SIGNAL(activated()),this,SLOT(main_slot_gr2())); 84 | connect(gr3_shortcut,SIGNAL(activated()),this,SLOT(main_slot_gr3())); 85 | connect(gr4_shortcut,SIGNAL(activated()),this,SLOT(main_slot_gr4())); 86 | connect(paste_gr1_shortcut,SIGNAL(activated()),this,SLOT(main_slot_pasteGr1())); 87 | connect(paste_gr2_shortcut,SIGNAL(activated()),this,SLOT(main_slot_pasteGr2())); 88 | connect(paste_gr3_shortcut,SIGNAL(activated()),this,SLOT(main_slot_pasteGr3())); 89 | connect(paste_gr4_shortcut,SIGNAL(activated()),this,SLOT(main_slot_pasteGr4())); 90 | 91 | connect(openFileLocation_shortCut,SIGNAL(activated()),this,SLOT(main_slot_openFileLocation())); 92 | 93 | connect(workerThread,SIGNAL(finished()),worker,SLOT(deleteLater())); 94 | connect(workerThread,SIGNAL(finished()),workerThread,SLOT(deleteLater())); 95 | worker->moveToThread(workerThread); 96 | workerThread->start(); 97 | on_actionNew_Tab_triggered(); 98 | } 99 | 100 | MainWindow::~MainWindow() 101 | { 102 | delete ui; 103 | workerThread->quit(); 104 | workerThread->wait(); 105 | } 106 | 107 | void MainWindow::on_actionOpen_triggered() 108 | { 109 | int liTempGobFileNamesSize = gobFileNames.size(); 110 | 111 | giDefaultDirCounter ++; 112 | 113 | if(giDefaultDirCounter > 1) { 114 | gsDefaultDir = ""; 115 | giDefaultDirCounter = 2; 116 | } 117 | 118 | if(this->giOpenWithFlag == 0){ 119 | gobFileNames.append(QFileDialog::getOpenFileNames(this 120 | ,"Open File" 121 | ,gsDefaultDir 122 | ,tr("All Files (*);;Text Files (*.txt);;Log files (*.log)"))); 123 | } 124 | 125 | gobFileNames = removeDuplicates(gobFileNames); 126 | 127 | if(!gobFileNames.isEmpty() && gobFileNames.size() > liTempGobFileNamesSize){ 128 | QString lsFileName = gobFileNames.at(giCurrentFileIndex); 129 | loadFile(lsFileName); 130 | } 131 | 132 | this->giOpenWithFlag = 0; 133 | } 134 | 135 | bool MainWindow::on_actionSave_As_triggered() 136 | { 137 | QString lsFileName; 138 | 139 | lsFileName = QFileDialog::getSaveFileName(this 140 | ,"Save File" 141 | ,"" 142 | ,tr("Text Files (*.txt);;All Files (*)")); 143 | 144 | giCurrentTabIndex = ui->tabWidget->currentIndex(); 145 | 146 | if(lsFileName != NULL && !lsFileName.isEmpty() && gobFilePathsHash.value(giCurrentTabIndex) != lsFileName){ 147 | gobFileNames.removeAt(gobFileNames.indexOf(gobFilePathsHash.value(giCurrentTabIndex))); 148 | gobFilePathsHash.remove(giCurrentTabIndex); 149 | gobFilePathsHash.insert(giCurrentTabIndex,lsFileName); 150 | return saveFile(lsFileName); 151 | } else { 152 | return false; 153 | } 154 | } 155 | 156 | bool MainWindow::on_actionSave_triggered() 157 | { 158 | QString lsFileName; 159 | giCurrentTabIndex = ui->tabWidget->currentIndex(); 160 | lsFileName = gobFilePathsHash.value(giCurrentTabIndex); 161 | QFile file(lsFileName); 162 | 163 | if(file.exists()){ 164 | return saveFile(lsFileName); 165 | }else{ 166 | return on_actionSave_As_triggered(); 167 | } 168 | } 169 | 170 | bool MainWindow::saveFile(QString asFileName, QString asText) 171 | { 172 | if(asFileName.isEmpty()){ 173 | return false; 174 | } 175 | 176 | QFile file(asFileName); 177 | 178 | if (!file.open(QIODevice::WriteOnly | QIODevice::Text)){ 179 | QMessageBox::critical(this,"Error","File could not be opened"); 180 | return false; 181 | } 182 | 183 | QTextStream out(&file); 184 | out << asText; 185 | file.close(); 186 | 187 | return true; 188 | } 189 | 190 | bool MainWindow::saveFile(QString asFileName) 191 | { 192 | QPlainTextEdit* lobPlainTextEdit = qobject_cast(ui->tabWidget->widget(giCurrentTabIndex)); 193 | if(!saveFile(asFileName,lobPlainTextEdit->toPlainText())) return false; 194 | ui->indicatorLabel->clear(); 195 | if(gobIsModifiedTextHash.contains(giCurrentTabIndex)) { 196 | gobIsModifiedTextHash.remove(giCurrentTabIndex); 197 | } 198 | gobIsModifiedTextHash.insert(giCurrentTabIndex,false); 199 | setCurrentTabNameFromFile(asFileName); 200 | this->setStatusBarTextAsLink(asFileName); 201 | if(!gobFileNames.contains(asFileName)){ 202 | gobFileNames.append(asFileName); 203 | giCurrentFileIndex ++; 204 | this->addRecentFiles(); 205 | } 206 | this->showTimedStatusMessage("File Saved!",1500); 207 | return true; 208 | } 209 | 210 | bool MainWindow::saveConfig() 211 | { 212 | QString configText = "[THEME]\n"; 213 | configText = configText + "themeFile=" + gsThemeFile + "\n"; 214 | configText = configText + "statusBarColor=" + gsStatusBarColor + "\n"; 215 | configText = configText + "[FONT]" + "\n"; 216 | configText = configText + "family=" + gobCurrentPlainTextEdit->fontInfo().family() + "\n"; 217 | configText = configText + "size=" + QString::number(gobCurrentPlainTextEdit->fontInfo().style()) + "\n"; 218 | configText = configText + "point=" + QString::number(gobCurrentPlainTextEdit->fontInfo().pointSize()) + "\n"; 219 | configText = configText + "[GEOMETRY]" + "\n"; 220 | configText = configText + "width=" + QString::number(this->geometry().width()) + "\n"; 221 | configText = configText + "height=" + QString::number(this->geometry().height()) + "\n"; 222 | configText = configText + "x=" + QString::number(this->geometry().x()) + "\n"; 223 | configText = configText + "y=" + QString::number(this->geometry().y()) + "\n"; 224 | configText = configText + "maximized=" + QString("%1").arg(this->isMaximized()) + "\n"; 225 | configText = configText + "[ALERTS]" + "\n"; 226 | configText = configText + "showEraseAlert=" + QString("%1").arg(this->gbShowEraseAndSaveMessageBox) + "\n"; 227 | configText = configText + "[FILESIZE]" + "\n"; 228 | configText = configText + "[RELOAD]" + "\n"; 229 | configText = configText + "delay=" + QString("%1").arg(giTimerDelay) + "\n"; 230 | configText = configText + "[RECENTS]" + "\n"; 231 | configText = configText + "recentFiles="; 232 | 233 | for(QString lsFile:gobRecentFiles){ 234 | configText = configText + "@@" + lsFile; 235 | } 236 | 237 | return saveFile("QNote_config.ini",configText); 238 | } 239 | 240 | bool MainWindow::loadConfig() 241 | { 242 | QString line; 243 | QScreen *screen = QGuiApplication::primaryScreen(); 244 | int liIsMaximized = 0; 245 | QFile *lobConfigFile = new QFile("QNote_config.ini"); 246 | 247 | if(!lobConfigFile->open(QFile::ReadOnly)){ 248 | gsSavedFont = "Arial"; 249 | giSavedFontStyle = 0; 250 | giSavedFontPointSize = 10; 251 | return false; 252 | } 253 | 254 | QTextStream lobInputStream(lobConfigFile); 255 | while (!lobInputStream.atEnd()) { 256 | line = lobInputStream.readLine(); 257 | if(line.startsWith("themeFile")) gsThemeFile = line.split("=").at(1); 258 | else if(line.startsWith("statusBarColor")) gsStatusBarColor = line.split("=").at(1); 259 | else if(line.startsWith("family")) gsSavedFont = line.split("=").at(1); 260 | else if(line.startsWith("maximized")) { 261 | 262 | if(line.split("=").at(1).toInt() == 1 ) { 263 | this->resize(585,453); 264 | this->move(screen->availableGeometry().center() - this->rect().center()); 265 | this->showMaximized(); 266 | liIsMaximized = 1; 267 | } 268 | } 269 | else if(line.startsWith("size")) giSavedFontStyle = line.split("=").at(1).toInt(); 270 | else if(line.startsWith("point")) giSavedFontPointSize = line.split("=").at(1).toInt(); 271 | else if(line.startsWith("width") && liIsMaximized == 0) this->resize(line.split("=").at(1).toInt(),this->geometry().height()); 272 | else if(line.startsWith("height") && liIsMaximized == 0) this->resize(this->geometry().width(),line.split("=").at(1).toInt()); 273 | else if(line.startsWith("x") && liIsMaximized == 0) this->move(line.split("=").at(1).toInt(),this->geometry().y()); 274 | else if(line.startsWith("y") && liIsMaximized == 0) this->move(this->geometry().x(),line.split("=").at(1).toInt()); 275 | else if(line.startsWith("showEraseAlert")) gbShowEraseAndSaveMessageBox = line.split("=").at(1).toInt(); 276 | else if(line.startsWith("delay")) giTimerDelay = line.split("=").at(1).toInt(); 277 | else if(line.startsWith("recentFiles")) { 278 | QStringList lobRecentList= line.split("@@"); 279 | lobRecentList.removeAt(0); 280 | for(QString lsRecentFile:lobRecentList){ 281 | gobRecentFiles.append(lsRecentFile); 282 | } 283 | this->addRecentFiles(); 284 | } 285 | } 286 | 287 | if(gsSavedFont.isEmpty() || gsSavedFont == "") { 288 | gsSavedFont = "Arial"; 289 | giSavedFontStyle = 0; 290 | giSavedFontPointSize = 10; 291 | } 292 | 293 | QFile style(gsThemeFile); 294 | 295 | if(style.exists() && style.open(QFile::ReadOnly)) { 296 | QString styleContents = QLatin1String(style.readAll()); 297 | style.close(); 298 | this->setStyleSheet(styleContents); 299 | } 300 | 301 | lobInputStream.flush(); 302 | lobConfigFile->close(); 303 | 304 | return true; 305 | } 306 | 307 | void MainWindow::on_actionAbout_QNote_triggered() 308 | { 309 | QMessageBox::about(this,"QNote 1.7.5", 310 | "" 317 | "

Simple text editor" 318 | "

Jaime A. Quiroga P." 319 | "

GTRONICK"); 320 | } 321 | 322 | void MainWindow::on_actionAbout_QT_triggered() 323 | { 324 | QMessageBox::aboutQt(this,"About QT5.11"); 325 | } 326 | 327 | void MainWindow::on_actionClose_Tab_triggered() 328 | { 329 | checkIfUnsaved(giCurrentTabIndex); 330 | } 331 | 332 | void MainWindow::on_actionNew_Tab_triggered() 333 | { 334 | disableAutoReload(); 335 | giTotalTabs ++; 336 | CustomTextEdit *lobPlainTexEdit = new CustomTextEdit(); 337 | lobPlainTexEdit->setPlaceholderText("Type Here..."); 338 | lobPlainTexEdit->setFrameShape(QFrame::NoFrame); 339 | lobPlainTexEdit->setLineWrapMode(QPlainTextEdit::WidgetWidth); 340 | lobPlainTexEdit->setAcceptDrops(true); 341 | int fontWidth = QFontMetrics(lobPlainTexEdit->currentCharFormat().font()).averageCharWidth(); 342 | lobPlainTexEdit->setTabStopDistance(TABCHARS * fontWidth ); 343 | QPalette p = lobPlainTexEdit->palette(); 344 | p.setColor(QPalette::Highlight, QColor(qRgb(200,0,0))); 345 | p.setColor(QPalette::HighlightedText, QColor(qRgb(255,255,255))); 346 | lobPlainTexEdit->setPalette(p); 347 | connect(lobPlainTexEdit,SIGNAL(textChanged()),this,SLOT(main_slot_textChanged())); 348 | connect(lobPlainTexEdit,SIGNAL(customTextEdit_signal_processDropEvent(QDropEvent*)),this,SLOT(main_slot_processDropEvent(QDropEvent*))); 349 | connect(lobPlainTexEdit,SIGNAL(cursorPositionChanged()),this,SLOT(main_slot_currentLineChanged())); 350 | connect(this,SIGNAL(main_signal_refreshHighlight()),lobPlainTexEdit,SLOT(highlightCurrentLine())); 351 | connect(gobSearchDialog,SIGNAL(search_signal_disableHighLight()),lobPlainTexEdit,SLOT(cte_slot_disableHighLight())); 352 | connect(gobSearchDialog,SIGNAL(search_signal_enableHighLight()),lobPlainTexEdit,SLOT(cte_slot_enableHighLight())); 353 | QFont lobFont(gsSavedFont, giSavedFontPointSize, giSavedFontStyle); 354 | lobPlainTexEdit->setFont(lobFont); 355 | giCurrentTabIndex = this->ui->tabWidget->addTab(lobPlainTexEdit,"New " + QString::number(giTotalTabs)); 356 | this->ui->tabWidget->setCurrentIndex(giCurrentTabIndex); 357 | gobIsModifiedTextHash.insert(giCurrentTabIndex,false); 358 | } 359 | 360 | void MainWindow::on_actionReload_file_triggered() 361 | { 362 | QString lsFileName = gobFilePathsHash.value(giCurrentTabIndex); 363 | 364 | if(checkFileExist(lsFileName)){ 365 | QFile *lobFile = new QFile(lsFileName); 366 | gbIsReloadFile = true; 367 | 368 | if(!gbIsAutoreloadEnabled) checkIfUnsaved(giCurrentTabIndex); 369 | 370 | if(gbSaveCancelled == false){ 371 | setCurrentTabNameFromFile(lsFileName); 372 | 373 | if(!lobFile->open(QIODevice::ReadOnly | QIODevice::Text)){ 374 | QMessageBox::critical(this,"Error","File could not be opened"); 375 | gbIsReloadFile = false; 376 | } 377 | emit main_signal_loadFile(lobFile); 378 | }else{ 379 | gbSaveCancelled = false; 380 | } 381 | }else{ 382 | gbIsReloadFile = false; 383 | if(gobTimer->isActive()){ 384 | gobTimer->blockSignals(true); 385 | gobTimer->stop(); 386 | disableAutoReload(); 387 | } 388 | } 389 | } 390 | 391 | void MainWindow::on_actionGo_to_line_triggered() 392 | { 393 | bool ok; 394 | int line_number = QInputDialog::getInt(this, tr("Go to"), 395 | tr("Go to line: "), 396 | 1, 397 | 1, 398 | gobCurrentPlainTextEdit->blockCount(), 399 | 1, 400 | &ok); 401 | if(ok){ 402 | int moves = line_number-(gobCurrentPlainTextEdit->textCursor().blockNumber() + 1); 403 | QTextCursor cursor = gobCurrentPlainTextEdit->textCursor(); 404 | if(moves){ 405 | if(moves<0) cursor.movePosition(QTextCursor::Up, QTextCursor::MoveAnchor, -moves); 406 | else cursor.movePosition(QTextCursor::Down, QTextCursor::MoveAnchor, moves); 407 | 408 | cursor.movePosition(QTextCursor::StartOfLine); 409 | 410 | gobCurrentPlainTextEdit->setTextCursor(cursor); 411 | } 412 | } 413 | } 414 | 415 | void MainWindow::on_actionFind_Replace_triggered() 416 | { 417 | gobSearchDialog->focusOnSearchInputText(); 418 | gobSearchDialog->setSearchText(this->gobCurrentPlainTextEdit->textCursor().selectedText()); 419 | gobSearchDialog->setVisible(true); 420 | } 421 | 422 | void MainWindow::on_actionWord_wrap_toggled(bool arg1) 423 | { 424 | if(arg1){ 425 | gobCurrentPlainTextEdit->setLineWrapMode(QPlainTextEdit::WidgetWidth); 426 | }else{ 427 | gobCurrentPlainTextEdit->setLineWrapMode(QPlainTextEdit::NoWrap); 428 | } 429 | } 430 | 431 | void MainWindow::on_actionLoad_theme_triggered() 432 | { 433 | gsThemeFile = QFileDialog::getOpenFileName(this, tr("Open Style"), 434 | "", 435 | tr("Style sheets (*.qss);;All files(*.*)")); 436 | 437 | if(gsThemeFile != NULL && gsThemeFile != ""){ 438 | QFile styleFile(gsThemeFile); 439 | styleFile.open(QFile::ReadOnly); 440 | QString StyleSheet = QLatin1String(styleFile.readAll()); 441 | this->setStyleSheet(StyleSheet); 442 | }else{ 443 | this->setStyleSheet(""); 444 | } 445 | 446 | emit main_signal_refreshHighlight(); 447 | } 448 | 449 | void MainWindow::on_actionSystem_theme_triggered() 450 | { 451 | this->setStyleSheet(""); 452 | gsThemeFile = ""; 453 | emit main_signal_refreshHighlight(); 454 | } 455 | 456 | void MainWindow::on_actionAuto_Reload_tail_f_toggled(bool arg1) 457 | { 458 | QString lsFileName = gobFilePathsHash.value(giCurrentTabIndex); 459 | gbIsAutoreloadEnabled = arg1; 460 | 461 | if(arg1 && checkFileExist(lsFileName)){ 462 | gobCurrentPlainTextEdit->clear(); 463 | QFile *lobFile = new QFile(lsFileName); 464 | emit main_signal_setCurrentFileSize(lobFile->size()); 465 | checkIfUnsaved(giCurrentTabIndex); 466 | ui->indicatorLabel->setToolTip("Auto Reload Active"); 467 | this->ui->indicatorLabel->setMovie(gobMovie); 468 | gobTimer->blockSignals(false); 469 | gobTimer->start(giTimerDelay); 470 | ui->indicatorLabel->movie()->start(); 471 | lockTextEditor(); 472 | }else{ 473 | gbIsReloadFile = false; 474 | gobCurrentPlainTextEdit->setReadOnly(false); 475 | gobCurrentPlainTextEdit->setTextInteractionFlags(Qt::TextEditorInteraction); 476 | ui->indicatorLabel->setToolTip(""); 477 | if(gobTimer->isActive()) gobTimer->stop(); 478 | if(ui->indicatorLabel->movie() != NULL) ui->indicatorLabel->movie()->stop(); 479 | ui->indicatorLabel->clear(); 480 | 481 | disconnect(ui->actionAuto_Reload_tail_f,SIGNAL(toggled(bool)),this,SLOT(on_actionAuto_Reload_tail_f_toggled(bool))); 482 | ui->actionAuto_Reload_tail_f->setChecked(false); 483 | connect(ui->actionAuto_Reload_tail_f,SIGNAL(toggled(bool)),this,SLOT(on_actionAuto_Reload_tail_f_toggled(bool))); 484 | 485 | if(!checkFileExist(lsFileName)){ 486 | if(showCustomMessage("ERROR","The file can't be loaded","Reload")){ 487 | gbIsAutoreloadEnabled = true; 488 | gobCurrentPlainTextEdit->clear(); 489 | ui->actionAuto_Reload_tail_f->setChecked(true); 490 | } 491 | } 492 | } 493 | } 494 | 495 | void MainWindow::on_actionAuto_Reload_delay_triggered() 496 | { 497 | bool lbOk; 498 | int liDelay = QInputDialog::getInt(this, tr("Auto Reload delay (ms)"), 499 | tr("milliseconds:"), giTimerDelay, 10, 5000, 1, &lbOk); 500 | if (lbOk) giTimerDelay = liDelay; 501 | if(gobTimer->isActive()){ 502 | gobTimer->stop(); 503 | gobTimer->start(giTimerDelay); 504 | } 505 | } 506 | 507 | void MainWindow::on_actionFont_triggered() 508 | { 509 | bool ok; 510 | QFont font = QFontDialog::getFont(&ok, QFont(gsSavedFont, giSavedFontPointSize), this); 511 | if (ok) { 512 | gobCurrentPlainTextEdit->setFont(font); 513 | giSavedFontPointSize = gobCurrentPlainTextEdit->fontInfo().pointSize(); 514 | giSavedFontStyle = gobCurrentPlainTextEdit->fontInfo().style(); 515 | gsSavedFont = gobCurrentPlainTextEdit->fontInfo().family(); 516 | } 517 | } 518 | 519 | void MainWindow::on_actionErase_and_save_triggered() 520 | { 521 | int ret = QMessageBox::Ok; 522 | 523 | if(this->gbShowEraseAndSaveMessageBox){ 524 | QMessageBox msgBox(this); 525 | msgBox.setWindowTitle("Warning!"); 526 | msgBox.setText("Do you want to erase and save the file contents?"); 527 | msgBox.setStandardButtons(QMessageBox::Ok | QMessageBox::Cancel); 528 | msgBox.setDefaultButton(QMessageBox::Ok); 529 | QCheckBox *lobCheckBox = new QCheckBox("Don't show again"); 530 | msgBox.setCheckBox(lobCheckBox); 531 | connect(lobCheckBox,SIGNAL(toggled(bool)),this,SLOT(main_slot_dontShowAgain(bool))); 532 | ret = msgBox.exec(); 533 | } 534 | 535 | if(ret == QMessageBox::Ok){ 536 | if(this->gbIsAutoreloadEnabled){ 537 | this->ui->actionAuto_Reload_tail_f->setChecked(false); 538 | } 539 | 540 | gobCurrentPlainTextEdit = qobject_cast(ui->tabWidget->widget(giCurrentTabIndex)); 541 | gobCurrentPlainTextEdit->clear(); 542 | this->on_actionSave_triggered(); 543 | 544 | if(!this->gbIsAutoreloadEnabled){ 545 | this->ui->actionAuto_Reload_tail_f->setChecked(true); 546 | } 547 | } 548 | } 549 | 550 | void MainWindow::on_actionReset_alerts_triggered() 551 | { 552 | this->gbShowEraseAndSaveMessageBox = true; 553 | } 554 | 555 | void MainWindow::on_actionTo_UPERCASE_triggered() 556 | { 557 | QTextCursor lobCursor = gobCurrentPlainTextEdit->textCursor(); 558 | QString lsText = lobCursor.selectedText().toUpper(); 559 | lobCursor.insertText(lsText); 560 | } 561 | 562 | void MainWindow::on_actionTo_lowercase_triggered() 563 | { 564 | QTextCursor lobCursor = gobCurrentPlainTextEdit->textCursor(); 565 | QString lsText = lobCursor.selectedText().toLower(); 566 | lobCursor.insertText(lsText); 567 | } 568 | 569 | void MainWindow::on_tabWidget_tabCloseRequested(int index) 570 | { 571 | checkIfUnsaved(index); 572 | } 573 | 574 | void MainWindow::main_slot_getTextEditText() 575 | { 576 | QPlainTextEdit* edit = qobject_cast(ui->tabWidget->widget(giCurrentTabIndex)); 577 | emit main_signal_setTextEdit(edit); 578 | } 579 | 580 | void MainWindow::main_slot_resetCursor() 581 | { 582 | QPlainTextEdit* edit = qobject_cast(ui->tabWidget->widget(giCurrentTabIndex)); 583 | edit->moveCursor(QTextCursor::Start); 584 | } 585 | 586 | void MainWindow::main_slot_tabChanged(int aIndex) 587 | { 588 | giCurrentTabIndex = aIndex; 589 | this->setStatusBarTextAsLink(gobFilePathsHash.value(aIndex)); 590 | gobCurrentPlainTextEdit = qobject_cast(ui->tabWidget->widget(giCurrentTabIndex)); 591 | main_slot_currentLineChanged(); 592 | QFont serifFont(gsSavedFont, giSavedFontPointSize, giSavedFontStyle); 593 | gobCurrentPlainTextEdit->setFont(serifFont); 594 | if(gobIsModifiedTextHash.value(aIndex)){ 595 | ui->indicatorLabel->setPixmap(QPixmap("://unsaved.png")); 596 | }else if(gbIsAutoreloadEnabled){ 597 | emit main_signal_setCurrentFileSize(0); 598 | ui->indicatorLabel->setToolTip("Auto Reload Active"); 599 | this->ui->indicatorLabel->setMovie(gobMovie); 600 | gobTimer->start(giTimerDelay); 601 | ui->indicatorLabel->movie()->start(); 602 | lockTextEditor(); 603 | gobCurrentPlainTextEdit->clear(); 604 | }else{ 605 | if(!gbIsAutoreloadEnabled) ui->indicatorLabel->clear(); 606 | gobCurrentPlainTextEdit->setReadOnly(false); 607 | gobCurrentPlainTextEdit->setTextInteractionFlags(Qt::TextEditorInteraction); 608 | } 609 | } 610 | 611 | void MainWindow::main_slot_tabMoved(int from, int to) 612 | { 613 | QString lsTemporalValue = gobFilePathsHash.value(to); 614 | gobFilePathsHash.insert(to,gobFilePathsHash.value(from)); 615 | gobFilePathsHash.insert(from,lsTemporalValue); 616 | 617 | bool lbTemporalValue = gobIsModifiedTextHash.value(to); 618 | gobIsModifiedTextHash.insert(to,gobIsModifiedTextHash.value(from)); 619 | gobIsModifiedTextHash.insert(from,lbTemporalValue); 620 | } 621 | 622 | void MainWindow::main_slot_textChanged() 623 | { 624 | if(gbIsOpenedFile == false && gobIsModifiedTextHash.value(giCurrentTabIndex) == false && !gbIsAutoreloadEnabled){ 625 | ui->indicatorLabel->setPixmap(QPixmap("://unsaved.png")); 626 | ui->indicatorLabel->setToolTip("Document unsaved"); 627 | gobIsModifiedTextHash.insert(giCurrentTabIndex,true); 628 | } 629 | } 630 | 631 | void MainWindow::main_slot_appendText(QString asText) 632 | { 633 | gobCurrentPlainTextEdit->setUndoRedoEnabled(false); 634 | 635 | QString lsFileName; 636 | 637 | gbIsOpenedFile = true; 638 | gobCurrentPlainTextEdit->clear(); 639 | gobCurrentPlainTextEdit->appendPlainText(asText); 640 | gobIsModifiedTextHash.insert(giCurrentTabIndex,false); 641 | gbIsOpenedFile = false; 642 | 643 | if(gbIsReloadFile){ 644 | gbIsReloadFile = false; 645 | }else{ 646 | main_slot_resetCursor(); 647 | } 648 | 649 | gobCurrentPlainTextEdit->setUndoRedoEnabled(true); 650 | 651 | if(giCurrentFileIndex < gobFileNames.length()){ 652 | lsFileName = gobFileNames.at(giCurrentFileIndex); 653 | loadFile(lsFileName); 654 | } 655 | } 656 | 657 | void MainWindow::main_slot_insertText(QString asText) 658 | { 659 | gbIsOpenedFile = true; 660 | QScrollBar *lobBar = gobCurrentPlainTextEdit->verticalScrollBar(); 661 | 662 | if(lobBar->value() == lobBar->maximum()) { 663 | gobCurrentPlainTextEdit->insertPlainText(asText); 664 | lockTextEditor(); 665 | } else { 666 | gobCurrentPlainTextEdit->insertPlainText(asText); 667 | } 668 | 669 | gobIsModifiedTextHash.insert(giCurrentTabIndex,false); 670 | gbIsOpenedFile = false; 671 | 672 | if(gbIsReloadFile){ 673 | gbIsReloadFile = false; 674 | } 675 | } 676 | 677 | void MainWindow::main_slot_processDropEvent(QDropEvent *event) 678 | { 679 | const QMimeData* mimeData = event->mimeData(); 680 | int liTempGobFileNamesSize = gobFileNames.size(); 681 | 682 | if (mimeData->hasUrls()){ 683 | QList urlList = mimeData->urls(); 684 | 685 | for (int i = 0; i < urlList.size(); i++) { 686 | if(!gobFileNames.contains(urlList.at(i).toLocalFile())){ 687 | gobFileNames.append(urlList.at(i).toLocalFile()); 688 | } 689 | } 690 | 691 | if(!gobFileNames.isEmpty() && gobFileNames.size() > liTempGobFileNamesSize){ 692 | QString lsFileName = gobFileNames.at(giCurrentFileIndex); 693 | loadFile(lsFileName); 694 | } 695 | event->acceptProposedAction(); 696 | } 697 | } 698 | 699 | void MainWindow::main_slot_currentLineChanged() 700 | { 701 | int liLine = gobCurrentPlainTextEdit->textCursor().blockNumber() + 1; 702 | int liCol = gobCurrentPlainTextEdit->textCursor().columnNumber() + 1; 703 | ui->lineNumberLabel->setText(QString("Line: %1, Col: %2").arg(liLine).arg(liCol)); 704 | } 705 | 706 | /** 707 | Muestra la barra de menú en caso de que esta se 708 | encuentre oculta. La oculta si está visible. 709 | */ 710 | void MainWindow::main_slot_showHideMenuBar() 711 | { 712 | if(ui->menuBar->isVisible()){ 713 | this->ui->menuBar->hide(); 714 | this->ui->tabWidget->tabBar()->hide(); 715 | }else{ 716 | this->ui->menuBar->show(); 717 | this->ui->tabWidget->tabBar()->show(); 718 | } 719 | } 720 | 721 | void MainWindow::main_slot_dontShowAgain(bool abValue) 722 | { 723 | this->gbShowEraseAndSaveMessageBox = !abValue; 724 | } 725 | 726 | /** 727 | Asigna el texto seleccionado al buffer 1. Si no hay nada 728 | seleccionado, se limpia el buffer. 729 | */ 730 | void MainWindow::main_slot_gr1() 731 | { 732 | gsGr1 = gobCurrentPlainTextEdit->textCursor().selectedText(); 733 | if(!gsGr1.isEmpty()){ 734 | ui->statusBar->setText("Group #1 assigned."); 735 | } 736 | else { 737 | ui->statusBar->setText("Group #1 cleared."); 738 | } 739 | 740 | QTimer::singleShot(1500,this,SLOT(main_slot_resetStatusBarText())); 741 | } 742 | 743 | /** 744 | Asigna el texto seleccionado al buffer 2. Si no hay nada 745 | seleccionado, se limpia el buffer. 746 | */ 747 | void MainWindow::main_slot_gr2() 748 | { 749 | gsGr2 = gobCurrentPlainTextEdit->textCursor().selectedText(); 750 | if(!gsGr2.isEmpty()){ 751 | ui->statusBar->setText("Group #2 assigned."); 752 | } 753 | else { 754 | ui->statusBar->setText("Group #2 cleared."); 755 | } 756 | 757 | QTimer::singleShot(1500,this,SLOT(main_slot_resetStatusBarText())); 758 | } 759 | 760 | /** 761 | Asigna el texto seleccionado al buffer 3. Si no hay nada 762 | seleccionado, se limpia el buffer. 763 | */ 764 | void MainWindow::main_slot_gr3() 765 | { 766 | gsGr3 = gobCurrentPlainTextEdit->textCursor().selectedText(); 767 | if(!gsGr3.isEmpty()){ 768 | ui->statusBar->setText("Group #3 assigned."); 769 | } 770 | else { 771 | ui->statusBar->setText("Group #3 cleared."); 772 | } 773 | 774 | QTimer::singleShot(1500,this,SLOT(main_slot_resetStatusBarText())); 775 | } 776 | 777 | /** 778 | Asigna el texto seleccionado al buffer 4. Si no hay nada 779 | seleccionado, se limpia el buffer. 780 | */ 781 | void MainWindow::main_slot_gr4() 782 | { 783 | gsGr4 = gobCurrentPlainTextEdit->textCursor().selectedText(); 784 | if(!gsGr4.isEmpty()){ 785 | ui->statusBar->setText("Group #4 assigned."); 786 | } 787 | else { 788 | ui->statusBar->setText("Group #4 cleared."); 789 | } 790 | 791 | QTimer::singleShot(1500,this,SLOT(main_slot_resetStatusBarText())); 792 | } 793 | 794 | /** 795 | Pega el texto contenido en el buffer 1 796 | */ 797 | void MainWindow::main_slot_pasteGr1() 798 | { 799 | gobCurrentPlainTextEdit->textCursor().insertText(gsGr1); 800 | } 801 | 802 | /** 803 | Pega el texto contenido en el buffer 2 804 | */ 805 | void MainWindow::main_slot_pasteGr2() 806 | { 807 | gobCurrentPlainTextEdit->textCursor().insertText(gsGr2); 808 | } 809 | 810 | /** 811 | Pega el texto contenido en el buffer 3 812 | */ 813 | void MainWindow::main_slot_pasteGr3() 814 | { 815 | gobCurrentPlainTextEdit->textCursor().insertText(gsGr3); 816 | } 817 | 818 | /** 819 | Pega el texto contenido en el buffer 4 820 | */ 821 | void MainWindow::main_slot_pasteGr4() 822 | { 823 | gobCurrentPlainTextEdit->textCursor().insertText(gsGr4); 824 | } 825 | 826 | void MainWindow::main_slot_openFileLocation() 827 | { 828 | if(!gobFilePathsHash.value(giCurrentTabIndex).isNull() && !gobFilePathsHash.value(giCurrentTabIndex).isEmpty()) { 829 | on_statusBar_linkActivated(gobFilePathsHash.value(giCurrentTabIndex)); 830 | } 831 | } 832 | 833 | /** 834 | Retorna el texto del status bar a su estado anterior. Se usa 835 | después de haber mostrado un texto temporalmente. 836 | */ 837 | void MainWindow::main_slot_resetStatusBarText() 838 | { 839 | this->setStatusBarTextAsLink(gobFilePathsHash.value(giCurrentTabIndex)); 840 | } 841 | 842 | void MainWindow::main_slot_loadFileFromAction(QAction *aobAction) 843 | { 844 | if(aobAction->text().compare("Clear list") != 0 && !gobFileNames.contains(aobAction->text())) { 845 | gobFileNames.append(aobAction->text()); 846 | loadFile(aobAction->text()); 847 | } else if(aobAction->text().compare("Clear list") == 0) { 848 | ui->menuOpen_Recent->clear(); 849 | gobRecentFiles.clear(); 850 | } 851 | } 852 | 853 | void MainWindow::main_slot_tailFile() 854 | { 855 | QString lsFileName = gobFilePathsHash.value(giCurrentTabIndex); 856 | 857 | if(checkFileExist(lsFileName)){ 858 | QFile *lobFile = new QFile(lsFileName); 859 | gbIsReloadFile = true; 860 | 861 | if(!gbIsAutoreloadEnabled) checkIfUnsaved(giCurrentTabIndex); 862 | 863 | if(gbSaveCancelled == false){ 864 | 865 | setCurrentTabNameFromFile(lsFileName); 866 | emit main_signal_tailFile(lobFile); 867 | }else{ 868 | gbSaveCancelled = false; 869 | } 870 | 871 | }else{ 872 | gbIsReloadFile = false; 873 | if(gobTimer->isActive()){ 874 | gobTimer->blockSignals(true); 875 | gobTimer->stop(); 876 | gbIsAutoreloadEnabled = false; 877 | ui->actionAuto_Reload_tail_f->setChecked(false); 878 | } 879 | } 880 | } 881 | 882 | void MainWindow::setCurrentTabNameFromFile(QString asFileName) 883 | { 884 | QString extension = ""; 885 | QString fileName = ""; 886 | 887 | if(!QFileInfo(asFileName).completeSuffix().isEmpty()){ 888 | extension = "."+QFileInfo(asFileName).completeSuffix(); 889 | } 890 | 891 | fileName = QFileInfo(asFileName).baseName() + extension; 892 | 893 | ui->tabWidget->setTabText(ui->tabWidget->currentIndex(),fileName); 894 | } 895 | 896 | void MainWindow::checkIfUnsaved(int index) 897 | { 898 | QMessageBox msgBox(this); 899 | msgBox.setWindowTitle("Warning!"); 900 | msgBox.setText("Do you want to save your changes?"); 901 | msgBox.setStandardButtons(QMessageBox::Save | QMessageBox::Discard | QMessageBox::Cancel); 902 | msgBox.setDefaultButton(QMessageBox::Save); 903 | 904 | if(gobIsModifiedTextHash.value(index) == true){ 905 | msgBox.setText(ui->tabWidget->tabText(index) + " has been modified."); 906 | int ret = msgBox.exec(); 907 | 908 | switch (ret) { 909 | case QMessageBox::Save: 910 | if(!gbIsReloadFile && !gbIsAutoreloadEnabled && on_actionSave_triggered()) closeTab(index); 911 | else{ 912 | ui->indicatorLabel->clear(); 913 | on_actionSave_triggered(); 914 | } 915 | break; 916 | case QMessageBox::Discard: 917 | if(!gbIsReloadFile && !gbIsAutoreloadEnabled) closeTab(index); 918 | else ui->indicatorLabel->clear(); 919 | break; 920 | case QMessageBox::Cancel: 921 | gbSaveCancelled = true; 922 | break; 923 | default: 924 | on_actionSave_triggered(); 925 | if(!gbIsReloadFile && !gbIsAutoreloadEnabled) closeTab(index); 926 | break; 927 | } 928 | }else{ 929 | if(!gbIsReloadFile && !gbIsAutoreloadEnabled) closeTab(index); 930 | } 931 | } 932 | 933 | bool MainWindow::checkFileExist(QString asFileName) 934 | { 935 | QFile *lobFile = new QFile(asFileName); 936 | 937 | if(!asFileName.isEmpty() && lobFile->exists()){ 938 | return true; 939 | } 940 | 941 | return false; 942 | } 943 | 944 | void MainWindow::closeTab(int index) 945 | { 946 | if(giTotalTabs > 1){ 947 | gobFileNames.removeAt(gobFileNames.indexOf(gobFilePathsHash.value(index))); 948 | giCurrentFileIndex = gobFileNames.length(); 949 | gobFilePathsHash.remove(index); 950 | for(int i = index; i < giTotalTabs; i ++){ 951 | gobFilePathsHash.insert(i,gobFilePathsHash.value(i + 1)); 952 | } 953 | 954 | gobIsModifiedTextHash.remove(index); 955 | 956 | for(int i = index; i < giTotalTabs; i ++){ 957 | gobIsModifiedTextHash.insert(i,gobIsModifiedTextHash.value(i + 1)); 958 | } 959 | 960 | this->setStatusBarTextAsLink(gobFilePathsHash.value(giCurrentTabIndex)); 961 | 962 | giTotalTabs --; 963 | this->ui->tabWidget->removeTab(index); 964 | }else{ 965 | giTotalTabs = 0; 966 | giCurrentTabIndex = 0; 967 | giCurrentFileIndex = 0; 968 | gobFileNames.clear(); 969 | gobIsModifiedTextHash.clear(); 970 | gobFilePathsHash.clear(); 971 | on_actionNew_Tab_triggered(); 972 | this->ui->tabWidget->removeTab(index); 973 | } 974 | } 975 | 976 | void MainWindow::loadFile(QString asFileName) 977 | { 978 | QFile *lobFile = new QFile(asFileName); 979 | 980 | if(!asFileName.isEmpty() && lobFile->exists()){ 981 | 982 | disableAutoReload(); 983 | 984 | emit main_signal_setCurrentFileSize(lobFile->size()); 985 | 986 | if((gobFilePathsHash.value(giCurrentTabIndex) != NULL && gobFilePathsHash.value(giCurrentTabIndex) != "") || gobIsModifiedTextHash.value(giCurrentTabIndex) == true){ 987 | on_actionNew_Tab_triggered(); 988 | } 989 | 990 | gobFilePathsHash.insert(giCurrentTabIndex,asFileName); 991 | setCurrentTabNameFromFile(asFileName); 992 | main_slot_tabChanged(giCurrentTabIndex); 993 | 994 | if(!lobFile->open(QIODevice::ReadOnly | QIODevice::Text)){ 995 | QMessageBox::critical(this,"Error","File could not be opened"); 996 | return; 997 | } 998 | 999 | gobCurrentPlainTextEdit = qobject_cast(ui->tabWidget->widget(giCurrentTabIndex)); 1000 | giCurrentFileIndex ++; 1001 | emit main_signal_loadFile(lobFile); 1002 | 1003 | addRecentFiles(); 1004 | 1005 | } else { 1006 | QMessageBox::warning(this,"Error!","The file " + asFileName + " can't be opened."); 1007 | gobFileNames.removeAt(giCurrentFileIndex); 1008 | } 1009 | } 1010 | 1011 | void MainWindow::setFileNameFromCommandLine(QStringList asFileNames) 1012 | { 1013 | gobFileNames = asFileNames; 1014 | this->giOpenWithFlag = 1; 1015 | this->on_actionOpen_triggered(); 1016 | } 1017 | 1018 | void MainWindow::setStatusBarTextAsLink(QString asText) 1019 | { 1020 | ui->statusBar->setText( 1021 | "" 1028 | "" + asText + ""); 1029 | } 1030 | 1031 | void MainWindow::closeEvent(QCloseEvent *event) 1032 | { 1033 | bool lbClose = true; 1034 | 1035 | for(int i = giTotalTabs - 1; i >= 0; i --){ 1036 | checkIfUnsaved(i); 1037 | if(gbSaveCancelled){ 1038 | i = 0; 1039 | gbSaveCancelled = false; 1040 | lbClose = false; 1041 | } 1042 | } 1043 | if(lbClose){ 1044 | saveConfig(); 1045 | event->accept(); 1046 | }else{ 1047 | event->ignore(); 1048 | } 1049 | } 1050 | 1051 | void MainWindow::dropEvent(QDropEvent *event) 1052 | { 1053 | const QMimeData* mimeData = event->mimeData(); 1054 | 1055 | if (mimeData->hasUrls()){ 1056 | QList urlList = mimeData->urls(); 1057 | 1058 | for (int i = 0; i < urlList.size(); i++) { 1059 | gobCurrentPlainTextEdit->appendPlainText(urlList.at(i).toLocalFile()); 1060 | } 1061 | 1062 | event->acceptProposedAction(); 1063 | } 1064 | } 1065 | 1066 | void MainWindow::dragEnterEvent(QDragEnterEvent *event) 1067 | { 1068 | event->acceptProposedAction(); 1069 | } 1070 | 1071 | /** 1072 | Ajusta el comportamiento de la ventana principal, de modo que 1073 | la mantiene encima de las demás en caso de activarse esta opcion. 1074 | @param checked True: Mantiene la ventana encima de las demás. False: 1075 | La ventana se oculta cuando pierde el foco. 1076 | */ 1077 | void MainWindow::on_actionAlways_on_top_triggered(bool checked) 1078 | { 1079 | Qt::WindowFlags flags = this->windowFlags(); 1080 | if (checked) { 1081 | this->setWindowFlags(flags | Qt::CustomizeWindowHint | Qt::WindowStaysOnTopHint); 1082 | }else { 1083 | this->setWindowFlags(flags ^ (Qt::CustomizeWindowHint | Qt::WindowStaysOnTopHint)); 1084 | } 1085 | 1086 | this->show(); 1087 | } 1088 | 1089 | /** 1090 | Función que se dispara cuando se hace click en un enlace, en la barra de estado. 1091 | Abre el directorio padre del archivo especificado en el texto. 1092 | @param link - Texto del enlace 1093 | */ 1094 | void MainWindow::on_statusBar_linkActivated(const QString &link) 1095 | { 1096 | if(!QDesktopServices::openUrl(QUrl::fromLocalFile(QFileInfo(link).absolutePath()))) 1097 | { 1098 | QMessageBox::critical(this,"ERROR","Cannot open containing folder."); 1099 | } 1100 | } 1101 | 1102 | /** 1103 | Agrega los archivos recientes al menu de archivos recientes. 1104 | */ 1105 | void MainWindow::addRecentFiles() 1106 | { 1107 | 1108 | for(int i = 0; i < gobFileNames.size(); i++){ 1109 | 1110 | 1111 | if(gobRecentFiles.size() < MAX_RECENT) { 1112 | gobRecentFiles.append(" "); 1113 | } 1114 | 1115 | int liLastArrayPosition = gobRecentFiles.size() - 1; 1116 | for(int j = liLastArrayPosition; j > 0; j--) { 1117 | gobRecentFiles.move(j - 1,j); 1118 | } 1119 | 1120 | gobRecentFiles.replace(0,gobFileNames.at(i)); 1121 | 1122 | gobRecentFiles = removeDuplicates(gobRecentFiles); 1123 | } 1124 | 1125 | ui->menuOpen_Recent->clear(); 1126 | 1127 | int i = 0; 1128 | 1129 | for(i = 0; i < gobRecentFiles.size(); i++){ 1130 | ui->menuOpen_Recent->addAction(gobRecentFiles.at(i)); 1131 | } 1132 | 1133 | ui->menuOpen_Recent->addSeparator(); 1134 | ui->menuOpen_Recent->addAction("Clear list"); 1135 | } 1136 | 1137 | void MainWindow::disableAutoReload() 1138 | { 1139 | if(gbIsAutoreloadEnabled) this->on_actionAuto_Reload_tail_f_toggled(false); 1140 | } 1141 | 1142 | QStringList MainWindow::removeDuplicates(QStringList aobList) 1143 | { 1144 | QStringList returnList = aobList; 1145 | int liFound = 0; 1146 | 1147 | for(int i = 0; i < returnList.size(); i++) { 1148 | for(int j = 0; j < returnList.size(); j++) { 1149 | if(returnList.at(i) == returnList.at(j)) { 1150 | liFound ++; 1151 | if(liFound > 1) { 1152 | returnList.removeAt(j); 1153 | liFound = 1; 1154 | } 1155 | } 1156 | } 1157 | 1158 | liFound = 0; 1159 | } 1160 | 1161 | return returnList; 1162 | } 1163 | 1164 | void MainWindow::lockTextEditor() 1165 | { 1166 | gobCurrentPlainTextEdit->setReadOnly(true); 1167 | QTextCursor lobCursor = gobCurrentPlainTextEdit->textCursor(); 1168 | lobCursor.setPosition(gobCurrentPlainTextEdit->toPlainText().size()); 1169 | gobCurrentPlainTextEdit->setTextCursor(lobCursor); 1170 | gobCurrentPlainTextEdit->setTextInteractionFlags(Qt::NoTextInteraction); 1171 | gobCurrentPlainTextEdit->verticalScrollBar()->setValue(gobCurrentPlainTextEdit->verticalScrollBar()->maximum()); 1172 | } 1173 | 1174 | bool MainWindow::showCustomMessage(QString asTitle, QString asText, QString asCustomButtonText) 1175 | { 1176 | QMessageBox *lobMesgBox = new QMessageBox(this); 1177 | lobMesgBox->setWindowTitle(asTitle); 1178 | lobMesgBox->setText(asText); 1179 | QPushButton *lobButton = new QPushButton(asCustomButtonText,lobMesgBox); 1180 | lobMesgBox->addButton(lobButton,QMessageBox::AcceptRole); 1181 | lobMesgBox->addButton(QMessageBox::Cancel); 1182 | lobMesgBox->exec(); 1183 | return lobMesgBox->clickedButton() == lobButton ? true : false; 1184 | } 1185 | 1186 | void MainWindow::showTimedStatusMessage(QString asMessage, int aiTimeMsecs) 1187 | { 1188 | ui->statusBar->setText(asMessage); 1189 | QTimer::singleShot(aiTimeMsecs,this,SLOT(main_slot_resetStatusBarText())); 1190 | } 1191 | 1192 | void MainWindow::on_actionErase_and_save_2_triggered() 1193 | { 1194 | int ret = QMessageBox::Ok; 1195 | 1196 | if(this->gbShowEraseAndSaveMessageBox){ 1197 | QMessageBox msgBox(this); 1198 | msgBox.setWindowTitle("Warning!"); 1199 | msgBox.setText("Do you want to erase and save the file contents?"); 1200 | msgBox.setStandardButtons(QMessageBox::Ok | QMessageBox::Cancel); 1201 | msgBox.setDefaultButton(QMessageBox::Ok); 1202 | QCheckBox *lobCheckBox = new QCheckBox("Don't show again"); 1203 | msgBox.setCheckBox(lobCheckBox); 1204 | connect(lobCheckBox,SIGNAL(toggled(bool)),this,SLOT(main_slot_dontShowAgain(bool))); 1205 | ret = msgBox.exec(); 1206 | } 1207 | 1208 | if(ret == QMessageBox::Ok){ 1209 | disableAutoReload(); 1210 | gobCurrentPlainTextEdit = qobject_cast(ui->tabWidget->widget(giCurrentTabIndex)); 1211 | gobCurrentPlainTextEdit->clear(); 1212 | this->on_actionSave_triggered(); 1213 | } 1214 | } 1215 | -------------------------------------------------------------------------------- /mainwindow.h: -------------------------------------------------------------------------------- 1 | #ifndef MAINWINDOW_H 2 | #define MAINWINDOW_H 3 | #define MAX_RECENT 20 4 | #define TABCHARS 4 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include "searchdialog.h" 13 | #include "customtextedit.h" 14 | #include "worker.h" 15 | 16 | namespace Ui { 17 | class MainWindow; 18 | } 19 | 20 | class MainWindow : public QMainWindow 21 | { 22 | Q_OBJECT 23 | 24 | public: 25 | explicit MainWindow(QWidget *parent = 0); 26 | void closeEvent(QCloseEvent *event); 27 | void dragEnterEvent(QDragEnterEvent *event); 28 | void setFileNameFromCommandLine(QStringList asFileNames); 29 | void setStatusBarTextAsLink(QString asText); 30 | void lockTextEditor(); 31 | bool showCustomMessage(QString asTitle, QString asText, QString asCustomButtonText); 32 | void showTimedStatusMessage(QString asMessage, int aiTimeMsecs); 33 | ~MainWindow(); 34 | 35 | signals: 36 | void main_signal_setTextEdit(QPlainTextEdit *textdit); 37 | void main_signal_loadFile(QFile *file); 38 | void main_signal_refreshHighlight(); 39 | void main_signal_tailFile(QFile *file); 40 | void main_signal_setCurrentFileSize(int aiFileSize); 41 | 42 | private slots: 43 | bool on_actionSave_As_triggered(); 44 | bool on_actionSave_triggered(); 45 | void main_slot_appendText(QString asText); 46 | void main_slot_currentLineChanged(); 47 | void main_slot_dontShowAgain(bool abValue); 48 | void main_slot_getTextEditText(); 49 | void main_slot_gr1(); 50 | void main_slot_gr2(); 51 | void main_slot_gr3(); 52 | void main_slot_gr4(); 53 | void main_slot_insertText(QString asText); 54 | void main_slot_loadFileFromAction(QAction *aobAction); 55 | void main_slot_openFileLocation(); 56 | void main_slot_pasteGr1(); 57 | void main_slot_pasteGr2(); 58 | void main_slot_pasteGr3(); 59 | void main_slot_pasteGr4(); 60 | void main_slot_processDropEvent(QDropEvent *event); 61 | void main_slot_resetCursor(); 62 | void main_slot_resetStatusBarText(); 63 | void main_slot_showHideMenuBar(); 64 | void main_slot_tabChanged(int aIndex); 65 | void main_slot_tabMoved(int from, int to); 66 | void main_slot_tailFile(); 67 | void main_slot_textChanged(); 68 | void on_actionAbout_QNote_triggered(); 69 | void on_actionAbout_QT_triggered(); 70 | void on_actionAlways_on_top_triggered(bool checked); 71 | void on_actionAuto_Reload_delay_triggered(); 72 | void on_actionAuto_Reload_tail_f_toggled(bool arg1); 73 | void on_actionClose_Tab_triggered(); 74 | void on_actionErase_and_save_triggered(); 75 | void on_actionFind_Replace_triggered(); 76 | void on_actionFont_triggered(); 77 | void on_actionGo_to_line_triggered(); 78 | void on_actionLoad_theme_triggered(); 79 | void on_actionNew_Tab_triggered(); 80 | void on_actionOpen_triggered(); 81 | void on_actionReload_file_triggered(); 82 | void on_actionReset_alerts_triggered(); 83 | void on_actionSystem_theme_triggered(); 84 | void on_actionTo_UPERCASE_triggered(); 85 | void on_actionTo_lowercase_triggered(); 86 | void on_actionWord_wrap_toggled(bool arg1); 87 | void on_statusBar_linkActivated(const QString &link); 88 | void on_tabWidget_tabCloseRequested(int index); 89 | void on_actionErase_and_save_2_triggered(); 90 | 91 | private: 92 | bool checkFileExist(QString asFileName); 93 | bool loadConfig(); 94 | bool saveConfig(); 95 | bool saveFile(QString asFileName, QString asText); 96 | bool saveFile(QString asFileName); 97 | void checkIfUnsaved(int index); 98 | void closeTab(int index); 99 | void loadFile(QString asFileName); 100 | void setCurrentTabNameFromFile(QString asFileName); 101 | void addRecentFiles(); 102 | void disableAutoReload(); 103 | QStringList removeDuplicates(QStringList aobList); 104 | 105 | Ui::MainWindow *ui; 106 | 107 | int giCurrentFileIndex; //indice para el archivo actual que se abrirá 108 | int giCurrentTabIndex; //indice para la pestaña actual 109 | int giDefaultDirCounter; //Contador de archivos abiertos mediante Open, para aegurar que la proxima vez que se abra un archivo, se cargue el directorio del ultimo abierto. 110 | int giOpenWithFlag; 111 | int giSavedFontPointSize; 112 | int giSavedFontStyle; 113 | int giTimerDelay; //Tiempo de espera en milisegundos para la recarga automática 114 | int giTotalTabs; //Total de pestañas abiertas 115 | 116 | bool gbShowEraseAndSaveMessageBox; //Bandera que indica se se muestra o no el QMessageBox de Borrado, guardado y recarga. 117 | bool gbIsOpenedFile; //Bandera que indica si se está abriendo un archivo 118 | bool gbIsReloadFile; //Bandera que indica si un archivo se ha recargado 119 | bool gbIsAutoreloadEnabled; //Bandera que indica si la recarga automatica esta activa 120 | bool gbSaveCancelled; //Bandera que indica si se canceló el guardado del archivo 121 | 122 | QHash gobFilePathsHash; //Mapa que almacena índice del tab y ruta de archivo 123 | QHash gobIsModifiedTextHash; //Mapa que almacena índice del tab, y si el archivo correspondiente ha sido modificado 124 | 125 | QString gsDefaultDir; //Cadena con la ruta del directorio por defecto a mostrar al abrir un archivo. 126 | QString gsGr1; 127 | QString gsGr2; 128 | QString gsGr3; 129 | QString gsGr4; 130 | QString gsSavedFont; 131 | QString gsThemeFile; //Ruta del archivo del tema usado 132 | QString gsStatusBarColor; 133 | 134 | QStringList gobFileNames; //Lista de archivos arrastrados o abiertos. 135 | QStringList gobRecentFiles; //Lista de archivos recientes. 136 | 137 | SearchDialog *gobSearchDialog; //Diálogo de buscar y reemplazar 138 | CustomTextEdit *gobCurrentPlainTextEdit; //Objeto que almacena el QPlainTextEdit actual 139 | QMovie *gobMovie; 140 | QThread *workerThread; //Hilo separado del hilo principal 141 | QTimer *gobTimer; //Temporizador para recarga automática de archivos 142 | Worker *worker; // 143 | 144 | 145 | 146 | protected: 147 | virtual void dropEvent(QDropEvent *event); 148 | }; 149 | 150 | #endif // MAINWINDOW_H 151 | -------------------------------------------------------------------------------- /mainwindow.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | MainWindow 4 | 5 | 6 | 7 | 0 8 | 0 9 | 585 10 | 453 11 | 12 | 13 | 14 | QNote 15 | 16 | 17 | 18 | :/note.png:/note.png 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 10 29 | 30 | 31 | 32 | true 33 | 34 | 35 | QTabWidget::South 36 | 37 | 38 | QTabWidget::Rounded 39 | 40 | 41 | -1 42 | 43 | 44 | true 45 | 46 | 47 | true 48 | 49 | 50 | false 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 0 61 | 0 62 | 63 | 64 | 65 | 66 | 200 67 | 15 68 | 69 | 70 | 71 | Drop files here... 72 | 73 | 74 | Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 0 83 | 0 84 | 85 | 86 | 87 | 88 | 16777215 89 | 16777215 90 | 91 | 92 | 93 | Line 1. Col 1. 94 | 95 | 96 | Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 15 105 | 15 106 | 107 | 108 | 109 | 110 | 15 111 | 15 112 | 113 | 114 | 115 | 116 | 117 | 118 | false 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 0 132 | 0 133 | 585 134 | 20 135 | 136 | 137 | 138 | 139 | &File 140 | 141 | 142 | 143 | Open Recent 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | &About 160 | 161 | 162 | 163 | 164 | 165 | 166 | &Tools 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | &Settings 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | Edit 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | &Open... 208 | 209 | 210 | Ctrl+O 211 | 212 | 213 | 214 | 215 | &Save 216 | 217 | 218 | Ctrl+S 219 | 220 | 221 | 222 | 223 | Save &As... 224 | 225 | 226 | Ctrl+Shift+S 227 | 228 | 229 | 230 | 231 | &About QNote 232 | 233 | 234 | 235 | 236 | About &QT 237 | 238 | 239 | 240 | 241 | &New Tab 242 | 243 | 244 | Ctrl+T 245 | 246 | 247 | 248 | 249 | &Close Tab 250 | 251 | 252 | Ctrl+W 253 | 254 | 255 | 256 | 257 | &Find && Replace 258 | 259 | 260 | Ctrl+F 261 | 262 | 263 | 264 | 265 | &Reload File 266 | 267 | 268 | F5 269 | 270 | 271 | 272 | 273 | true 274 | 275 | 276 | true 277 | 278 | 279 | &Word wrap 280 | 281 | 282 | Alt+W 283 | 284 | 285 | 286 | 287 | &Go to line... 288 | 289 | 290 | Ctrl+G 291 | 292 | 293 | 294 | 295 | Load theme 296 | 297 | 298 | 299 | 300 | System theme 301 | 302 | 303 | 304 | 305 | true 306 | 307 | 308 | Auto Reload (tail -f) 309 | 310 | 311 | F6 312 | 313 | 314 | 315 | 316 | Auto Reload delay 317 | 318 | 319 | 320 | 321 | true 322 | 323 | 324 | false 325 | 326 | 327 | Always on top 328 | 329 | 330 | Ctrl+Shift+N 331 | 332 | 333 | 334 | 335 | Font 336 | 337 | 338 | 339 | 340 | Open Recent ... 341 | 342 | 343 | 344 | 345 | Erase, save and Auto Reload 346 | 347 | 348 | F7 349 | 350 | 351 | 352 | 353 | Reset alerts 354 | 355 | 356 | 357 | 358 | Set Maximun file size 359 | 360 | 361 | 362 | 363 | UPERCASE 364 | 365 | 366 | Ctrl+U 367 | 368 | 369 | 370 | 371 | lowercase 372 | 373 | 374 | Ctrl+Shift+U 375 | 376 | 377 | 378 | 379 | Erase and save 380 | 381 | 382 | F8 383 | 384 | 385 | 386 | 387 | Clear list 388 | 389 | 390 | 391 | 392 | 393 | 394 | CustomTabWidget 395 | QTabWidget 396 |

customtabwidget.h
397 | 1 398 | 399 | 400 | 401 | 402 | 403 | 404 | 405 | -------------------------------------------------------------------------------- /searchdialog.cpp: -------------------------------------------------------------------------------- 1 | #include "searchdialog.h" 2 | #include "ui_searchdialog.h" 3 | #include 4 | #include 5 | 6 | /** 7 | Object's constructor. 8 | */ 9 | SearchDialog::SearchDialog(QWidget *parent) : 10 | QDialog(parent), 11 | ui(new Ui::SearchDialog) 12 | { 13 | ui->setupUi(this); 14 | gbReplaceClicked = false; 15 | gbSearchClicked = false; 16 | gbReplaceAllClicked = false; 17 | giSearchCondition = 0; 18 | giSearchFlag = 0; 19 | } 20 | 21 | void SearchDialog::focusOnSearchInputText() 22 | { 23 | this->ui->seachDialog_searchLineEdit->setFocus(); 24 | } 25 | 26 | void SearchDialog::setSearchText(QString asText) 27 | { 28 | this->ui->seachDialog_searchLineEdit->setText(asText); 29 | } 30 | 31 | int SearchDialog::adjustExtraSelections(QPlainTextEdit *aobTextEdit, QString asTextToSearch) 32 | { 33 | QList extraSelections; 34 | QTextEdit::ExtraSelection selection; 35 | QColor lineColor = QColor(Qt::yellow).lighter(100); 36 | selection.format.setBackground(lineColor); 37 | selection.format.setForeground(QColor(0,0,0)); 38 | aobTextEdit->extraSelections().clear(); 39 | 40 | while(aobTextEdit->find(asTextToSearch,giSearchCondition)){ 41 | selection.cursor = aobTextEdit->textCursor(); 42 | extraSelections.append(selection); 43 | } 44 | extraSelections.append(selection); 45 | aobTextEdit->setExtraSelections(extraSelections); 46 | return extraSelections.size() > 0 ? extraSelections.size() -1 : 0; 47 | } 48 | 49 | /** 50 | Object's destructor. 51 | */ 52 | SearchDialog::~SearchDialog() 53 | { 54 | delete ui; 55 | } 56 | 57 | /** 58 | Action triggered when the search button is clicked. 59 | This will rise a flag, which will be used in the 60 | setTextEdit method. 61 | */ 62 | void SearchDialog::on_searchDialog_searchButton_clicked() 63 | { 64 | gbSearchClicked = true; 65 | emit search_signal_disableHighLight(); 66 | emit search_signal_getTextEditText(); 67 | } 68 | 69 | /** 70 | Action triggered when the replace button is clicked. 71 | This will rise a flag, which will be used in the 72 | setTextEdit method. 73 | */ 74 | void SearchDialog::on_searchDialog_replaceButton_clicked() 75 | { 76 | gbReplaceClicked = true; 77 | emit(search_signal_getTextEditText()); 78 | } 79 | 80 | /** 81 | Action triggered when the replace all button is clicked. 82 | This will rise a flag, which will be used in the 83 | setTextEdit method. 84 | */ 85 | void SearchDialog::on_searchDialog_replaceAllButton_clicked() 86 | { 87 | gbReplaceAllClicked = true; 88 | emit(search_signal_getTextEditText()); 89 | } 90 | 91 | /** 92 | Action triggered when the swap button is clicked. 93 | This will swap the text into the "search" line edit, with the 94 | text into the "reaplace all" line edit. 95 | */ 96 | void SearchDialog::on_gobSwapTextButton_clicked() 97 | { 98 | QString lsReplace; 99 | lsReplace = this->ui->seachDialog_searchLineEdit->text(); 100 | this->ui->seachDialog_searchLineEdit->setText(this->ui->searchDialog_replaceLineEdit->text()); 101 | this->ui->searchDialog_replaceLineEdit->setText(lsReplace); 102 | } 103 | 104 | void SearchDialog::resetSearch() 105 | { 106 | giCurrentOcurrence = 0; 107 | giOcurrencesFound = 0; 108 | giOcurrencesFound = this->adjustExtraSelections(gobTextEdit,ui->seachDialog_searchLineEdit->text()); 109 | emit(search_signal_resetCursor()); 110 | } 111 | 112 | /** 113 | Creates a copy of the TextEdit object, and dependign on 114 | the clicked button, the according action modifications 115 | will be made. Then, the new object will be send in a signal 116 | to the main UI. 117 | */ 118 | void SearchDialog::search_slot_setTextEdit(QPlainTextEdit *textEdit) 119 | { 120 | this->gobTextEdit = textEdit; 121 | 122 | if(gbReplaceAllClicked){ 123 | gbReplaceAllClicked = false; 124 | gobTextEdit->extraSelections().clear(); 125 | gobTextEdit->textCursor().clearSelection(); 126 | 127 | 128 | emit(search_signal_resetCursor()); 129 | this->adjustExtraSelections(gobTextEdit,ui->seachDialog_searchLineEdit->text()); 130 | gobTextEdit->extraSelections().removeLast(); 131 | 132 | QTextCursor cursor; 133 | 134 | for(int i=0; i < gobTextEdit->extraSelections().length() - 1; i++){ 135 | cursor = gobTextEdit->extraSelections().at(i).cursor; 136 | cursor.insertText(ui->searchDialog_replaceLineEdit->text()); 137 | } 138 | 139 | gobTextEdit->extraSelections().clear(); 140 | giSearchFlag = 0; 141 | 142 | }else if(gbSearchClicked){ 143 | gbSearchClicked = false; 144 | 145 | if(giSearchFlag == 0) { 146 | emit(search_signal_resetCursor()); 147 | this->resetSearch(); 148 | giSearchFlag = 1; 149 | } 150 | 151 | if(gobTextEdit->find(ui->seachDialog_searchLineEdit->text(),giSearchCondition)){ 152 | giCurrentOcurrence ++; 153 | } else { 154 | emit(search_signal_resetCursor()); 155 | giCurrentOcurrence = 0; 156 | if(gobTextEdit->find(ui->seachDialog_searchLineEdit->text(),giSearchCondition)) { 157 | giCurrentOcurrence ++; 158 | } else { 159 | giSearchFlag = 0; 160 | this->resetSearch(); 161 | } 162 | } 163 | 164 | ui->ocurrencesCounterLabel->setText(QString("%1/%2").arg(giCurrentOcurrence).arg(giOcurrencesFound)); 165 | 166 | }else if(gbReplaceClicked){ 167 | gbReplaceClicked = false; 168 | if(gobTextEdit->textCursor().selectedText() == ui->seachDialog_searchLineEdit->text()){ 169 | gobTextEdit->textCursor().insertText(ui->searchDialog_replaceLineEdit->text()); 170 | } 171 | } 172 | emit search_signal_enableHighLight(); 173 | } 174 | 175 | 176 | 177 | void SearchDialog::on_caseSentive_checkBox_stateChanged(int arg1) 178 | { 179 | if(arg1 == 2) { 180 | giSearchCondition = giSearchCondition | QTextDocument::FindCaseSensitively; 181 | } else { 182 | giSearchCondition = giSearchCondition ^ QTextDocument::FindCaseSensitively; 183 | } 184 | } 185 | 186 | void SearchDialog::on_wholeWords_checkBox_stateChanged(int arg1) 187 | { 188 | if(arg1 == 2) { 189 | giSearchCondition = giSearchCondition | QTextDocument::FindWholeWords; 190 | } else { 191 | giSearchCondition = giSearchCondition ^ QTextDocument::FindWholeWords; 192 | } 193 | } 194 | 195 | void SearchDialog::on_backward_checkBox_stateChanged(int arg1) 196 | { 197 | if(arg1 == 2) { 198 | giSearchCondition = giSearchCondition | QTextDocument::FindBackward; 199 | } else { 200 | giSearchCondition = giSearchCondition ^ QTextDocument::FindBackward; 201 | } 202 | } 203 | -------------------------------------------------------------------------------- /searchdialog.h: -------------------------------------------------------------------------------- 1 | #ifndef SEARCHDIALOG_H 2 | #define SEARCHDIALOG_H 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | namespace Ui { 9 | class SearchDialog; 10 | } 11 | 12 | class SearchDialog : public QDialog 13 | { 14 | Q_OBJECT 15 | 16 | public: 17 | explicit SearchDialog(QWidget *parent = 0); 18 | void focusOnSearchInputText(); 19 | void setSearchText(QString asText); 20 | void resetSearch(); 21 | int adjustExtraSelections(QPlainTextEdit *aobTextEdit, QString asTextToSearch); 22 | ~SearchDialog(); 23 | 24 | signals: 25 | void search_signal_resetCursor(); 26 | void search_signal_getTextEditText(); 27 | void search_signal_disableHighLight(); 28 | void search_signal_enableHighLight(); 29 | 30 | private slots: 31 | void on_searchDialog_searchButton_clicked(); 32 | void on_searchDialog_replaceButton_clicked(); 33 | void on_searchDialog_replaceAllButton_clicked(); 34 | void search_slot_setTextEdit(QPlainTextEdit *textEdit); 35 | void on_gobSwapTextButton_clicked(); 36 | void on_caseSentive_checkBox_stateChanged(int arg1); 37 | void on_wholeWords_checkBox_stateChanged(int arg1); 38 | void on_backward_checkBox_stateChanged(int arg1); 39 | 40 | private: 41 | Ui::SearchDialog *ui; 42 | int giLine; 43 | int giCurrentOcurrence; 44 | int giOcurrencesFound; 45 | int giSearchFlag; 46 | QTextDocument::FindFlags giSearchCondition; 47 | bool gbReplaceAllClicked; 48 | bool gbReplaceClicked; 49 | bool gbSearchClicked; 50 | QString gsFoundText; 51 | QPlainTextEdit *gobTextEdit; 52 | }; 53 | 54 | #endif // SEARCHDIALOG_H 55 | -------------------------------------------------------------------------------- /searchdialog.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | SearchDialog 4 | 5 | 6 | Qt::NonModal 7 | 8 | 9 | 10 | 0 11 | 0 12 | 300 13 | 122 14 | 15 | 16 | 17 | 18 | 300 19 | 250 20 | 21 | 22 | 23 | Search & replace 24 | 25 | 26 | 27 | 28 | 29 | Find... 30 | 31 | 32 | 33 | 34 | 35 | 36 | Search 37 | 38 | 39 | 40 | 41 | 42 | 43 | Replace with... 44 | 45 | 46 | 47 | 48 | 49 | 50 | Replace 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 45 61 | 16777215 62 | 63 | 64 | 65 | Qt::TabFocus 66 | 67 | 68 | Swap 69 | 70 | 71 | 72 | 73 | 74 | 75 | Qt::Horizontal 76 | 77 | 78 | 79 | 40 80 | 20 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 0/0 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | Replace all 98 | 99 | 100 | 101 | 102 | 103 | 104 | Case sensitive 105 | 106 | 107 | 108 | 109 | 110 | 111 | Whole words 112 | 113 | 114 | 115 | 116 | 117 | 118 | Backward 119 | 120 | 121 | 122 | 123 | 124 | 125 | seachDialog_searchLineEdit 126 | searchDialog_searchButton 127 | searchDialog_replaceLineEdit 128 | searchDialog_replaceButton 129 | gobSwapTextButton 130 | searchDialog_replaceAllButton 131 | 132 | 133 | 134 | 135 | -------------------------------------------------------------------------------- /tabwidget.h: -------------------------------------------------------------------------------- 1 | #ifndef TABWIDGET_H 2 | #define TABWIDGET_H 3 | #include 4 | 5 | class TabWidget : public QTabWidget 6 | { 7 | Q_OBJECT 8 | public: 9 | TabWidget(); 10 | }; 11 | 12 | #endif // TABWIDGET_H 13 | -------------------------------------------------------------------------------- /worker.cpp: -------------------------------------------------------------------------------- 1 | #include "worker.h" 2 | #include 3 | #include 4 | 5 | Worker::Worker(QObject *parent) : QObject(parent){ 6 | giFileSize = 0; 7 | } 8 | 9 | void Worker::worker_slot_loadFile(QFile *file) 10 | { 11 | QString line = ""; 12 | QString text = ""; 13 | QTextStream in(file); 14 | while (!in.atEnd()) { 15 | line = in.readLine(); 16 | text.append(line + "\n"); 17 | } 18 | in.flush(); 19 | file->close(); 20 | text.remove(text.lastIndexOf("\n"),1); 21 | emit worker_signal_appendText(text); 22 | } 23 | 24 | void Worker::worker_slot_tailFile(QFile *file) 25 | { 26 | if(file->size() > giFileSize) { 27 | int liDiff = file->size() - giFileSize; 28 | if(file->open(QIODevice::ReadOnly | QIODevice::Text)) { 29 | if(file->seek(giFileSize)) { 30 | QString lsText = QString(file->read(liDiff)); 31 | emit worker_signal_insertText(lsText); 32 | giFileSize = file->size(); 33 | } 34 | file->close(); 35 | } 36 | } else { 37 | giFileSize = file->size(); 38 | } 39 | } 40 | 41 | void Worker::worker_slot_setCurrentFileSize(int aiFileSize) 42 | { 43 | this->giFileSize = aiFileSize; 44 | } 45 | 46 | -------------------------------------------------------------------------------- /worker.h: -------------------------------------------------------------------------------- 1 | #ifndef WORKER_H 2 | #define WORKER_H 3 | 4 | #include 5 | #include 6 | 7 | class Worker : public QObject 8 | { 9 | Q_OBJECT 10 | public: 11 | explicit Worker(QObject *parent = 0); 12 | 13 | signals: 14 | void worker_signal_appendText(QString line); 15 | void worker_signal_insertText(QString line); 16 | 17 | public slots: 18 | void worker_slot_loadFile(QFile *file); 19 | void worker_slot_tailFile(QFile *file); 20 | void worker_slot_setCurrentFileSize(int aiFileSize); 21 | 22 | private: 23 | int giFileSize; 24 | }; 25 | 26 | #endif // WORKER_H 27 | --------------------------------------------------------------------------------