Reputation: 2135
I want to read objects from an XML file and i need to handle 2 exceptions : when the file cannot be opened and when the file content cannot be loaded. (incorrectly formated) I have written the following function to read the content from the file and 2 clases for the exceptions. The problem is that when i run my application and i am trying to load a file with different format then XML, instead of a frindly message which informs that there is an exception, i have a debug error : abort() is called. What i am not doing well? reading function
QList<Vehicle> VehicleHelper::readVehicles(QString fileName){
QList<Vehicle> vehicles;
Vehicle newVehicle;
QFile file(fileName);
QDomDocument document;
if(!file.open(QIODevice::ReadOnly | QIODevice::Text)){
throw FileCannotBeOpenException();
}
else{
if(!document.setContent(&file)){
throw InvalidXMLContentException();
}
file.close();
}
QDomElement root = document.firstChildElement();
QDomNodeList carElements = root.elementsByTagName("Car");
for(int i = 0; i < carElements.size(); i++){
QDomNode carNode = carElements.at(i);
QDomElement carElement = carNode.toElement();
QString carID = carElement.attribute("ID");
//if the idNumber is null, generate one
if(carID.isEmpty()){
QUuid newId = Vehicle::generateID();
newVehicle.setVehicleId(newId);
}
else {
QUuid id;
try{
id = QUuid::QUuid(carID);
} catch(QException &ex){
continue;
}
newVehicle.setVehicleId(id);
}
}
the call of the function
void MainWindow::on_actionOpen_triggered()
{
if(isModified){
QMessageBox msgBox;
QString message = "There are unsaved changes! Do you proceed? ";
msgBox.setWindowTitle("Save Changes");
msgBox.setText(message);
msgBox.addButton("Don't save",QMessageBox::NoRole);
msgBox.addButton(QMessageBox::Save);
msgBox.addButton(QMessageBox::Cancel);
msgBox.setIcon(QMessageBox::Question);
int result = msgBox.exec();
if(result == QMessageBox::Save){
VehicleHelper::writeVehicles(cars,filename);
msgBox.close();
} else {
QString fileName = QFileDialog::getOpenFileName(this,"Open file");
if(!fileName.isEmpty()){
setFileName(fileName);
QFile file(fileName);
try {
cars = VehicleHelper::readVehicles(fileName);
} catch(FileCannotBeOpenException &ex) {
QMessageBox msgBox;
msgBox.setIcon(QMessageBox::Critical);
msgBox.setWindowTitle("Message!");
msgBox.setText("Failed to open file");
msgBox.setDefaultButton(QMessageBox::Ok);
msgBox.exec();
return;
} catch(InvalidXMLContentException &ex){
QMessageBox msgBox;
msgBox.setIcon(QMessageBox::Critical);
msgBox.setWindowTitle("Message!");
msgBox.setText("Failed to load data!");
msgBox.setDefaultButton(QMessageBox::Ok);
msgBox.exec();
return;
}
setTakenNumbersList(cars);
//set data to the table view
populate(cars);
}
}
} else {
QString fileName = QFileDialog::getOpenFileName(this,"Open file");
if(!fileName.isEmpty()){
setFileName(fileName);
QFile file(fileName);
if(file.open(QFile::ReadOnly | QFile::Text)){
cars = VehicleHelper::readVehicles(fileName);
setTakenNumbersList(cars);
file.close();
//set data to the table view
populate(cars);
ui->actionAdd->setEnabled(true);
ui->actionBy_name->setEnabled(true);
ui->actionBy_registration_date->setEnabled(true);
ui->actionBy_registration_number->setEnabled(true);
ui->actionBy_revision_date->setEnabled(true);
ui->actionBy_type->setEnabled(true);
ui->actionClear_Search->setEnabled(true);
ui->actionDelete->setEnabled(true);
ui->actionEdit->setEnabled(true);
ui->actionSave->setEnabled(true);
ui->actionSave_As->setEnabled(true);
}
}
}
}
main
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
try{
w.show();
} catch(QException &ex){
}
return a.exec();
}
Upvotes: 1
Views: 2253
Reputation: 98425
The exceptions are thrown from code that runs in the event loop, specifically they will reach the QCoreApplication::notify()
. This one is indirectly called from a.exec()
, via an intervening operating system event loop call.
Thus you can't merely wrap a.exec()
in a try/catch. You must reimplement QCoreApplication::notify()
as follows:
class MyApplication : public QApplication
{
public:
MyApplication(int & c, char ** a) : QApplication(c,a) {}
virtual bool notify(QObject * obj, QEvent * ev) {
bool rc = true;
try {
rc = QApplication::notify(obj, ev);
}
catch (QException &ex) {
...
}
return rc;
}
};
int main(...) {
MyApplication app(...);
...
}
Another problem with your code is that it screams to use the State Machine Framework. You should have states that represent file being open and closed, and intermediate states when e.g. an "unsaved changes" dialog box is shown. Then you won't have the ui->actionXYZ->setEnabled(true)
littered around the code. Assuming you have a fileOpen
state, you'd have
fileOpen->assignProperty(ui->actionBy_name, "setEnabled", true);
...
Then when the file is open, you emit a signal that is attached to a signal transition in the state machine. The state machine will do the rest - it will enable/disable actions for you, etc.
Upvotes: 2