1 /* time_shift_dialog.cpp
2  *
3  * Wireshark - Network traffic analyzer
4  * By Gerald Combs <gerald@wireshark.org>
5  * Copyright 1998 Gerald Combs
6  *
7  * SPDX-License-Identifier: GPL-2.0-or-later
8  */
9 
10 #include "time_shift_dialog.h"
11 #include <ui_time_shift_dialog.h>
12 
13 #include "wireshark_application.h"
14 
15 #include <ui/time_shift.h>
16 #include <ui/qt/utils/color_utils.h>
17 
18 #include <QStyleOption>
19 
TimeShiftDialog(QWidget * parent,capture_file * cf)20 TimeShiftDialog::TimeShiftDialog(QWidget *parent, capture_file *cf) :
21     QDialog(parent),
22     ts_ui_(new Ui::TimeShiftDialog),
23     cap_file_(cf),
24     apply_button_(NULL)
25 {
26     ts_ui_->setupUi(this);
27     setWindowTitle(wsApp->windowTitleString(tr("Time Shift")));
28     apply_button_ = ts_ui_->buttonBox->button(QDialogButtonBox::Apply);
29     apply_button_->setDefault(true);
30     connect(apply_button_, SIGNAL(clicked()), this, SLOT(applyTimeShift()));
31 
32     QStyleOption style_opt;
33     int rb_label_offset =  ts_ui_->shiftAllButton->style()->subElementRect(QStyle::SE_RadioButtonContents, &style_opt).left();
34     int cb_label_offset =  ts_ui_->shiftAllButton->style()->subElementRect(QStyle::SE_CheckBoxContents, &style_opt).left();
35     setStyleSheet(QString(
36                       "QCheckBox#setTwoCheckBox {"
37                       "  margin-left: %1px;"
38                       "}"
39                       "QLabel#extrapolateLabel {"
40                       "  margin-left: %2px;"
41                       "}"
42                       )
43                   .arg(rb_label_offset)
44                   .arg(rb_label_offset + cb_label_offset)
45                   );
46 
47     if (cap_file_) {
48         if (cap_file_->current_frame) {
49             ts_ui_->setOneFrameLineEdit->setText(QString::number(cap_file_->current_frame->num));
50         } else {
51             ts_ui_->setOneFrameLineEdit->setText(QString::number(cap_file_->first_displayed));
52         }
53         ts_ui_->setTwoFrameLineEdit->setText(QString::number(cap_file_->last_displayed));
54     }
55 
56     ts_ui_->shiftAllButton->setChecked(true);
57     ts_ui_->setTwoCheckBox->setChecked(false);
58     enableWidgets();
59 }
60 
~TimeShiftDialog()61 TimeShiftDialog::~TimeShiftDialog()
62 {
63     delete ts_ui_;
64 }
65 
enableWidgets()66 void TimeShiftDialog::enableWidgets()
67 {
68     bool enable_two = ts_ui_->setOneButton->isChecked();
69     bool enable_apply = false;
70 
71     ts_ui_->setTwoCheckBox->setEnabled(enable_two);
72     ts_ui_->setTwoFrameLineEdit->setEnabled(enable_two);
73     ts_ui_->setTwoToLabel->setEnabled(enable_two);
74     ts_ui_->setTwoTimeLineEdit->setEnabled(enable_two);
75     ts_ui_->extrapolateLabel->setEnabled(enable_two && ts_ui_->setTwoCheckBox->isChecked());
76 
77     if (ts_ui_->shiftAllButton->isChecked()) {
78         if (ts_ui_->shiftAllTimeLineEdit->syntaxState() == SyntaxLineEdit::Valid)
79             enable_apply = true;
80     } else if (ts_ui_->setOneButton->isChecked()) {
81         bool set_two_valid = false;
82         if (ts_ui_->setTwoCheckBox->isChecked()) {
83             if (ts_ui_->setTwoFrameLineEdit->syntaxState() == SyntaxLineEdit::Valid &&
84                     ts_ui_->setTwoTimeLineEdit->syntaxState() == SyntaxLineEdit::Valid) {
85                 set_two_valid = true;
86             }
87         } else {
88             set_two_valid = true;
89         }
90         if (set_two_valid &&
91                 ts_ui_->setOneFrameLineEdit->syntaxState() == SyntaxLineEdit::Valid &&
92                 ts_ui_->setOneTimeLineEdit->syntaxState() == SyntaxLineEdit::Valid) {
93             enable_apply = true;
94         }
95     } else if (ts_ui_->unshiftAllButton->isChecked()) {
96         enable_apply = true;
97     }
98 
99     if (syntax_err_.isEmpty()) {
100         ts_ui_->errorLabel->clear();
101         ts_ui_->errorLabel->setStyleSheet(" QLabel { margin-top: 0.5em; }");
102     } else {
103         ts_ui_->errorLabel->setText(syntax_err_);
104         ts_ui_->errorLabel->setStyleSheet(QString(
105                     "QLabel {"
106                     "  margin-top: 0.5em;"
107                     "  background-color: %2;"
108                     "}"
109                     )
110                 .arg(ColorUtils::warningBackground().name())
111                 );
112     }
113     apply_button_->setEnabled(enable_apply);
114 }
115 
checkFrameNumber(SyntaxLineEdit & frame_le)116 void TimeShiftDialog::checkFrameNumber(SyntaxLineEdit &frame_le)
117 {
118     bool frame_valid;
119     guint frame_num = frame_le.text().toUInt(&frame_valid);
120 
121     syntax_err_.clear();
122     if (frame_le.text().isEmpty()) {
123         frame_le.setSyntaxState(SyntaxLineEdit::Empty);
124     } else if (!frame_valid || !cap_file_ || frame_num < 1 || frame_num > cap_file_->count) {
125         frame_le.setSyntaxState(SyntaxLineEdit::Invalid);
126         if (cap_file_) {
127             syntax_err_ = QString(tr("Frame numbers must be between 1 and %1.").arg(cap_file_->count));
128         } else {
129             syntax_err_ = tr("Invalid frame number.");
130         }
131     } else {
132         frame_le.setSyntaxState(SyntaxLineEdit::Valid);
133     }
134 }
135 
checkDateTime(SyntaxLineEdit & time_le)136 void TimeShiftDialog::checkDateTime(SyntaxLineEdit &time_le)
137 {
138     int Y, M, D, h, m;
139     long double s;
140     const gchar *err_str;
141 
142     syntax_err_.clear();
143     if (time_le.text().isEmpty()) {
144         time_le.setSyntaxState(SyntaxLineEdit::Empty);
145     } else if ((err_str = time_string_parse(time_le.text().toUtf8().constData(),
146                                  &Y, &M, &D, NULL, &h, &m, &s)) != NULL) {
147         syntax_err_ = err_str;
148         time_le.setSyntaxState(SyntaxLineEdit::Invalid);
149     } else {
150         time_le.setSyntaxState(SyntaxLineEdit::Valid);
151     }
152 }
153 
on_shiftAllButton_toggled(bool)154 void TimeShiftDialog::on_shiftAllButton_toggled(bool)
155 {
156     enableWidgets();
157 }
158 
on_setOneButton_toggled(bool)159 void TimeShiftDialog::on_setOneButton_toggled(bool)
160 {
161     enableWidgets();
162 }
163 
on_unshiftAllButton_toggled(bool)164 void TimeShiftDialog::on_unshiftAllButton_toggled(bool)
165 {
166     enableWidgets();
167 }
168 
on_setTwoCheckBox_toggled(bool)169 void TimeShiftDialog::on_setTwoCheckBox_toggled(bool)
170 {
171     enableWidgets();
172 }
173 
on_shiftAllTimeLineEdit_textChanged(const QString & sa_text)174 void TimeShiftDialog::on_shiftAllTimeLineEdit_textChanged(const QString &sa_text)
175 {
176     int h, m;
177     long double s;
178     gboolean neg;
179     const gchar *err_str;
180 
181     syntax_err_.clear();
182     if (sa_text.isEmpty()) {
183         ts_ui_->shiftAllTimeLineEdit->setSyntaxState(SyntaxLineEdit::Empty);
184     } else if ((err_str = time_string_parse(sa_text.toUtf8().constData(),
185                                  NULL, NULL, NULL, &neg, &h, &m, &s)) != NULL) {
186         syntax_err_ = err_str;
187         ts_ui_->shiftAllTimeLineEdit->setSyntaxState(SyntaxLineEdit::Invalid);
188     } else {
189         ts_ui_->shiftAllTimeLineEdit->setSyntaxState(SyntaxLineEdit::Valid);
190     }
191     ts_ui_->shiftAllButton->setChecked(true);
192     enableWidgets();
193 }
194 
on_setOneFrameLineEdit_textChanged(const QString &)195 void TimeShiftDialog::on_setOneFrameLineEdit_textChanged(const QString &)
196 {
197     checkFrameNumber(*ts_ui_->setOneFrameLineEdit);
198     ts_ui_->setOneButton->setChecked(true);
199     enableWidgets();
200 }
on_setOneTimeLineEdit_textChanged(const QString &)201 void TimeShiftDialog::on_setOneTimeLineEdit_textChanged(const QString &)
202 {
203     checkDateTime(*ts_ui_->setOneTimeLineEdit);
204     ts_ui_->setOneButton->setChecked(true);
205     enableWidgets();
206 }
207 
on_setTwoFrameLineEdit_textChanged(const QString &)208 void TimeShiftDialog::on_setTwoFrameLineEdit_textChanged(const QString &)
209 {
210     checkFrameNumber(*ts_ui_->setTwoFrameLineEdit);
211     if (ts_ui_->setTwoCheckBox->isEnabled())
212         ts_ui_->setTwoCheckBox->setChecked(true);
213     enableWidgets();
214 }
215 
on_setTwoTimeLineEdit_textChanged(const QString &)216 void TimeShiftDialog::on_setTwoTimeLineEdit_textChanged(const QString &)
217 {
218     checkDateTime(*ts_ui_->setTwoTimeLineEdit);
219     if (ts_ui_->setTwoCheckBox->isEnabled())
220         ts_ui_->setTwoCheckBox->setChecked(true);
221     enableWidgets();
222 }
223 
applyTimeShift()224 void TimeShiftDialog::applyTimeShift()
225 {
226     const gchar *err_str = NULL;
227 
228     if (!cap_file_ || cap_file_->state == FILE_CLOSED) return;
229 
230     syntax_err_.clear();
231     if (cap_file_->state == FILE_READ_IN_PROGRESS) {
232         syntax_err_ = tr("Time shifting is not available capturing packets.");
233     } else if (ts_ui_->shiftAllButton->isChecked()) {
234         err_str = time_shift_all(cap_file_,
235                                  ts_ui_->shiftAllTimeLineEdit->text().toUtf8().constData());
236     } else if (ts_ui_->setOneButton->isChecked()) {
237         if (!ts_ui_->setTwoCheckBox->isChecked()) {
238             err_str = time_shift_settime(cap_file_,
239                                          ts_ui_->setOneFrameLineEdit->text().toUInt(),
240                                          ts_ui_->setOneTimeLineEdit->text().toUtf8().constData()
241                                          );
242         } else {
243             err_str = time_shift_adjtime(cap_file_,
244                                          ts_ui_->setOneFrameLineEdit->text().toUInt(),
245                                          ts_ui_->setOneTimeLineEdit->text().toUtf8().constData(),
246                                          ts_ui_->setTwoFrameLineEdit->text().toUInt(),
247                                          ts_ui_->setTwoTimeLineEdit->text().toUtf8().constData()
248                                          );
249         }
250     } else if (ts_ui_->unshiftAllButton->isChecked()) {
251         err_str = time_shift_undo(cap_file_);
252     }
253 
254     if (err_str) {
255         syntax_err_ = err_str;
256     } else {
257         emit timeShifted();
258     }
259 
260     enableWidgets();
261 }
262 
on_buttonBox_helpRequested()263 void TimeShiftDialog::on_buttonBox_helpRequested()
264 {
265     wsApp->helpTopicAction(HELP_TIME_SHIFT_DIALOG);
266 }
267