1 /*
2 # PostgreSQL Database Modeler (pgModeler)
3 #
4 # Copyright 2006-2020 - Raphael Araújo e Silva <raphael@pgmodeler.io>
5 #
6 # This program is free software: you can redistribute it and/or modify
7 # it under the terms of the GNU General Public License as published by
8 # the Free Software Foundation version 3.
9 #
10 # This program is distributed in the hope that it will be useful,
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 # GNU General Public License for more details.
14 #
15 # The complete text of GPLv3 is at LICENSE file on source code root directory.
16 # Also, you can get the complete GNU General Public License at <http://www.gnu.org/licenses/>
17 */
18
19 #include "crashhandlerform.h"
20 #include "messagebox.h"
21 #include "pgmodeleruins.h"
22
23 const QString CrashHandlerForm::AnalysisMode("-analysis-mode");
24
CrashHandlerForm(bool analysis_mode,QWidget * parent,Qt::WindowFlags f)25 CrashHandlerForm::CrashHandlerForm(bool analysis_mode, QWidget *parent, Qt::WindowFlags f) : BugReportForm(parent, f)
26 {
27 QFile input;
28 QString buf;
29 QWidget *wgt=new QWidget;
30 QHBoxLayout *layout=new QHBoxLayout;
31
32 setWindowTitle(tr("pgModeler crash handler"));
33
34 stack_txt=new QPlainTextEdit(this);
35 stack_txt->setReadOnly(true);
36 stack_txt->setFont(QFont("Source Code Pro"));
37 stack_txt->setLineWrapMode(QPlainTextEdit::NoWrap);
38
39 layout->addWidget(stack_txt);
40 layout->setContentsMargins(4,4,4,4);
41 wgt->setLayout(layout);
42
43 logo_lbl->setPixmap(QPixmap(QString(":/imagens/imagens/crashhandler.png")));
44 report_twg->addTab(wgt, tr("Stack trace"));
45
46 //Open for reading the stack trace file generated on the last crash
47 input.setFileName(GlobalAttributes::getTemporaryFilePath(GlobalAttributes::StacktraceFile));
48 input.open(QFile::ReadOnly);
49
50 if(input.isOpen())
51 {
52 buf=input.readAll();
53 input.close();
54
55 //Removes the stack trace file
56 QDir stack_file;
57 stack_file.remove(GlobalAttributes::getTemporaryFilePath(GlobalAttributes::StacktraceFile));
58
59 //Shows the stacktrace loaded on the widget
60 stack_txt->setPlainText(buf);
61 }
62
63 //Creating an input field in order to select the input report file
64 input_wgt=new QWidget(this);
65 input_wgt->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);
66
67 layout=new QHBoxLayout(input_wgt);
68 layout->setContentsMargins(0, 0, 0, 0);
69
70 input_lbl=new QLabel(input_wgt);
71 input_lbl->setText(tr("Input:"));
72 layout->addWidget(input_lbl);
73
74 input_sel = new FileSelectorWidget(this);
75 input_sel->setFileDialogTitle(tr("Select bug report file"));
76 input_sel->setFileMode(QFileDialog::ExistingFile);
77 input_sel->setAcceptMode(QFileDialog::AcceptOpen);
78 input_sel->setNameFilters({ tr("pgModeler bug report (*.bug)"), tr("All files (*.*)") });
79 input_sel->setToolTip(tr("Load report file for analysis"));
80 layout->addWidget(input_sel);
81
82 save_tb=new QToolButton(input_wgt);
83 save_tb->setIcon(QPixmap(PgModelerUiNs::getIconPath("salvar")));
84 save_tb->setSizePolicy(attach_tb->sizePolicy());
85 save_tb->setToolButtonStyle(attach_tb->toolButtonStyle());
86 save_tb->setIconSize(attach_tb->iconSize());
87 save_tb->setToolTip(tr("Save the attached model file on the filesystem"));
88 save_tb->setEnabled(false);
89 attach_wgt->layout()->addWidget(save_tb);
90
91 report_tab_grid->removeWidget(details_gb);
92 report_tab_grid->removeWidget(output_wgt);
93 report_tab_grid->removeWidget(message_frm);
94
95 report_tab_grid->addWidget(input_wgt);
96 report_tab_grid->addWidget(details_gb);
97 report_tab_grid->addWidget(output_wgt);
98 report_tab_grid->addWidget(message_frm);
99
100 setAnalysisMode(analysis_mode);
101
102 connect(input_sel, SIGNAL(s_fileSelected(QString)), this, SLOT(loadReport(QString)));
103 connect(input_sel, SIGNAL(s_selectorCleared()), model_txt, SLOT(clear()));
104 connect(input_sel, SIGNAL(s_selectorCleared()), details_txt, SLOT(clear()));
105 connect(input_sel, SIGNAL(s_selectorCleared()), stack_txt, SLOT(clear()));
106 connect(save_tb, SIGNAL(clicked()), this, SLOT(saveModel()));
107
108 connect(model_txt, &QPlainTextEdit::textChanged, [&](){
109 save_tb->setEnabled(!model_txt->toPlainText().isEmpty());
110 });
111 }
112
loadReport(QString filename)113 void CrashHandlerForm::loadReport(QString filename)
114 {
115 QFile input;
116 QFileInfo fi;
117 char *buf=nullptr;
118 Messagebox msgbox;
119
120 fi.setFile(filename);
121 input.setFileName(filename);
122 input.open(QFile::ReadOnly);
123
124 //Raises an error if the file could not be opened
125 if(!input.isOpen())
126 msgbox.show(Exception::getErrorMessage(ErrorCode::FileDirectoryNotAccessed).arg(filename), Messagebox::ErrorIcon);
127 else
128 {
129 QByteArray uncomp_buf;
130 QString buf_aux, str_aux;
131 int i, idx;
132 QPlainTextEdit *txt_widgets[]={ details_txt, model_txt , stack_txt};
133
134 //Creates a text buffer
135 buf=new char[fi.size()];
136
137 //Reads the file storing it on the buffer
138 input.read(buf, fi.size());
139 input.close();
140
141 //Uncompress the buffer
142 uncomp_buf.append(buf, fi.size());
143 uncomp_buf=qUncompress(uncomp_buf);
144
145 delete[](buf);
146 buf=nullptr;
147
148 buf_aux=QString(uncomp_buf.data());
149 i=idx=0;
150
151 //Showing the sections of the uncompressed buffer on the respective widgets
152 while(i < buf_aux.size() && idx <= 2)
153 {
154 if(buf_aux.at(i).toLatin1()!=CharDelimiter)
155 str_aux.append(buf_aux.at(i));
156 else
157 {
158 txt_widgets[idx++]->setPlainText(str_aux);
159 str_aux.clear();
160 }
161 i++;
162 }
163 }
164 }
165
saveModel()166 void CrashHandlerForm::saveModel()
167 {
168 QFileDialog file_dlg;
169
170 try
171 {
172 file_dlg.setDefaultSuffix(QString("dbm"));
173 file_dlg.setWindowTitle(tr("Save model"));
174 file_dlg.setNameFilter(tr("Database model (*.dbm);;All files (*.*)"));
175 file_dlg.setFileMode(QFileDialog::AnyFile);
176 file_dlg.setAcceptMode(QFileDialog::AcceptSave);
177 file_dlg.setModal(true);
178
179 if(file_dlg.exec()==QFileDialog::Accepted)
180 {
181 QFile output(file_dlg.selectedFiles().at(0));
182 QByteArray buf;
183
184 output.open(QFile::WriteOnly);
185
186 if(!output.isOpen())
187 throw Exception(Exception::getErrorMessage(ErrorCode::FileDirectoryNotWritten).arg(file_dlg.selectedFiles().at(0)),
188 ErrorCode::FileDirectoryNotWritten,__PRETTY_FUNCTION__,__FILE__,__LINE__);
189
190 buf.append(model_txt->toPlainText());
191 output.write(buf.data(),buf.size());
192 output.close();
193 }
194 }
195 catch(Exception &e)
196 {
197 Messagebox msgbox;
198 msgbox.show(e);
199 }
200 }
201
setAnalysisMode(bool value)202 void CrashHandlerForm::setAnalysisMode(bool value)
203 {
204 output_wgt->setEnabled(!value);
205 attach_tb->setEnabled(!value);
206 attach_mod_chk->setEnabled(!value);
207 save_tb->setVisible(value);
208
209 create_btn->setVisible(!value);
210 input_wgt->setVisible(value);
211
212 if(value)
213 {
214 title_lbl->setText(tr("pgModeler crash handler"));
215 msg_lbl->setText(tr("Bug report analysis mode activated."));
216 }
217 else
218 {
219 title_lbl->setText(tr("Oops! pgModeler just crashed!"));
220 msg_lbl->setText(tr("We apologize for what happened! It is clear that a nasty bug caused that. Please fill out the form below describing your actions before pgModeler quit unexpectedly. This will help on bug extermination and improve the software."));
221 }
222 }
223
generateReportBuffer()224 QByteArray CrashHandlerForm::generateReportBuffer()
225 {
226 QByteArray buf=BugReportForm::generateReportBuffer();
227 buf.append(stack_txt->toPlainText().toUtf8());
228 buf.append(CharDelimiter);
229
230 return buf;
231 }
232