1 /*
2     SPDX-FileCopyrightText: 2007 Nicolas Ternisien <nicolas.ternisien@gmail.com>
3 
4     SPDX-License-Identifier: GPL-2.0-or-later
5 */
6 
7 #include "logViewModel.h"
8 
9 #include "logLine.h"
10 #include "view.h"
11 
12 #include "logModeItemBuilder.h"
13 #include "logViewWidget.h"
14 #include "logViewWidgetItem.h"
15 
16 #include "ksystemlog_debug.h"
17 
18 #include "ksystemlogConfig.h"
19 
LogViewModel(LogViewWidget * logViewWidget)20 LogViewModel::LogViewModel(LogViewWidget *logViewWidget)
21     : QObject(logViewWidget)
22 {
23     mLogViewWidget = logViewWidget;
24 }
25 
~LogViewModel()26 LogViewModel::~LogViewModel()
27 {
28 }
29 
logLineAlreadyExists(LogLine * line) const30 bool LogViewModel::logLineAlreadyExists(LogLine *line) const
31 {
32     LogViewWidgetItem *item = mLogViewWidget->findItem(line);
33     if (item) {
34         return true;
35     }
36 
37     return false;
38 }
39 
logLines() const40 QList<LogLine *> LogViewModel::logLines() const
41 {
42     return mLogViewWidget->logLines();
43 }
44 
itemCount() const45 int LogViewModel::itemCount() const
46 {
47     return mLogViewWidget->itemCount();
48 }
49 
isEmpty() const50 bool LogViewModel::isEmpty() const
51 {
52     if (mLogViewWidget->itemCount() == 0) {
53         return true;
54     }
55 
56     return false;
57 }
58 
removeRecentStatusOfLogLines()59 void LogViewModel::removeRecentStatusOfLogLines()
60 {
61     // The older lines are no longer recent
62     const auto items = mLogViewWidget->items();
63     for (LogViewWidgetItem *item : items) {
64         item->logLine()->setRecent(false);
65     }
66 }
67 
startingMultipleInsertions()68 void LogViewModel::startingMultipleInsertions()
69 {
70     bool hasLocked = false;
71 
72     // Check the lock before adding this as locker
73     if (lockMultipleInsertions()) {
74         hasLocked = true;
75     }
76 
77     // Add a lock
78     mConcurrentMultipleInsertions++;
79 
80     if (hasLocked) {
81         qCDebug(KSYSTEMLOG) << "Starting multiple insertions...";
82 
83         Q_EMIT processingMultipleInsertions(true);
84 
85         mLogViewWidget->setUpdatesEnabled(false);
86 
87         // Remove all recent states of previous log lines
88         removeRecentStatusOfLogLines();
89     }
90 }
91 
endingMultipleInsertions(Analyzer::ReadingMode readingMode,int insertedLogLineCount)92 void LogViewModel::endingMultipleInsertions(Analyzer::ReadingMode readingMode, int insertedLogLineCount)
93 {
94     // Remove a lock
95     mConcurrentMultipleInsertions--;
96 
97     if (lockMultipleInsertions()) {
98         qCDebug(KSYSTEMLOG) << "Ending multiple insertions...";
99 
100         // Scroll to the newest item if some lines have been added
101         if (insertedLogLineCount > 0) {
102             mLogViewWidget->scrollToNewestItem();
103         }
104 
105         if (readingMode == Analyzer::FullRead) {
106             mLogViewWidget->resizeColumns();
107         }
108 
109         qCDebug(KSYSTEMLOG) << "Enabling log view widget refresh...";
110         mLogViewWidget->setUpdatesEnabled(true);
111 
112         Q_EMIT processingMultipleInsertions(false);
113     }
114 }
115 
lockMultipleInsertions()116 bool LogViewModel::lockMultipleInsertions()
117 {
118     if (mConcurrentMultipleInsertions == 0) {
119         return true;
120     }
121 
122     // Debug messages
123     if (mConcurrentMultipleInsertions > 0) {
124         qCDebug(KSYSTEMLOG) << "Existing multiple insertions request is still active";
125     } else if (mConcurrentMultipleInsertions < 0) {
126         qCCritical(KSYSTEMLOG) << "Existing multiple insertions forgot to call this method";
127     }
128 
129     return false;
130 }
131 
isProcessingMultipleInsertions() const132 bool LogViewModel::isProcessingMultipleInsertions() const
133 {
134     if (mConcurrentMultipleInsertions == 0) {
135         return false;
136     } else {
137         return true;
138     }
139 }
140 
clear()141 void LogViewModel::clear()
142 {
143     mLogViewWidget->clear();
144 
145     // Reinit Oldest item
146     mOldestItem = nullptr;
147 }
148 
isNewer(LogLine * newLine) const149 bool LogViewModel::isNewer(LogLine *newLine) const
150 {
151     // No element in the list in this case
152     if (!mOldestItem) {
153         return true;
154     }
155 
156     if (newLine->isNewerThan(*(mOldestItem->logLine()))) {
157         return true;
158     }
159 
160     return false;
161 }
162 
removeOldestLogLine()163 void LogViewModel::removeOldestLogLine()
164 {
165     // qCDebug(KSYSTEMLOG) << "Removing oldest log line";
166 
167     if (isEmpty()) {
168         return;
169     }
170 
171     if (!mOldestItem) {
172         qCWarning(KSYSTEMLOG) << "Oldest item is null";
173         return;
174     }
175 
176     // Remove the oldest item from the list
177     mLogViewWidget->takeTopLevelItem(mLogViewWidget->indexOfTopLevelItem(mOldestItem));
178 
179     delete mOldestItem;
180     mOldestItem = nullptr;
181 
182     // Find the next oldest item
183     const auto items{mLogViewWidget->items()};
184     for (LogViewWidgetItem *item : items) {
185         if (!mOldestItem) {
186             mOldestItem = item;
187             continue;
188         }
189 
190         if (mOldestItem->logLine()->isNewerThan(*(item->logLine()))) {
191             mOldestItem = item;
192         }
193     }
194 }
195 
insert(LogLine * line)196 void LogViewModel::insert(LogLine *line)
197 {
198     // The item is automatically added to the LogViewWidget
199     auto item = new LogViewWidgetItem(mLogViewWidget, line);
200 
201     // Update the oldest item
202     if (!mOldestItem) {
203         mOldestItem = item;
204     } else if (mOldestItem->logLine()->isNewerThan(*line)) {
205         mOldestItem = item;
206     }
207 }
208 
insertNewLogLine(LogLine * line)209 bool LogViewModel::insertNewLogLine(LogLine *line)
210 {
211     // If the Delete Duplicated Line option is checked
212     if (KSystemLogConfig::deleteDuplicatedLines()) {
213         if (logLineAlreadyExists(line)) {
214             delete line;
215             return false;
216         }
217     }
218 
219     // If there is still space in the buffer
220     if (itemCount() < KSystemLogConfig::maxLines()) {
221         insert(line);
222 
223         return true;
224     }
225     // If the line is newer, it can be inserted
226     else if (isNewer(line)) {
227         removeOldestLogLine();
228         insert(line);
229 
230         return true;
231     }
232 
233     // qCDebug(KSYSTEMLOG) << "Do not insert an old line : " << line->logItems();
234 
235     return false;
236 }
237