Prompt user to save changes when closing MFC view - c++

I have an MFC MDI application, in which it is possible for documents to have multiple views, and for users to customise and then save layout data for the views. This data is associated with the views, not the documents.
I would like to prompt the users to save if they choose to close a view with unsaved layout changes, and am running into problems, as it seems MFC is only geared towards changes in the document. Here are some approaches I've tried:
Override CDocument::SaveModified function, which gets called by the framework when a document is closed. In this function, I send a message to all the document's views, which can then check for unsaved changes and prompt the user.
Perform the check inside the View's destructor.
Perform the check inside the View's OnClose handler
Each of these approaches has problems. (1) is the best, but it fails to deal with cases where there are several views onto one document, and the user closes one of the views. As the document is still open, SaveModified is not called.
The problem with (2) is that on application shutdown, the application has already disappeard by the time any CView destrutors are called. This can leave an orphan dialog box open on the desktop. This is also the case if I try performing the check inside OnDestroy.
I can't get (3) to work - I can't get my views to respond to WM_CLOSE.
Currently, my best solution is to do both (1) and (2), but this requires some smelly logic to prevent the app from prompting the user to save view changes twice on app shutdown.
Anyone know of a better way of doing this? Where is the correct place to hook in?

I'm not sure if it is your solution, but I have several views that can not close on condition and I handle them in DestroyWindow( ). And a message box there does come up over the app before it closes down. So try using DestroyWindow( ) rather than the destructor.

Concur.
ON_WM_DESTROY()
afx_msg void OnDestroy();
does the trick. It will not prevent the window from closing, but the question didn't request it.

Related

AgGrid Detect changing on columns/filters/sortings events

I'm using ag-grid and I'd like to save the layout/state of the user. Pretty much something like this
This solution forces the user to click on the button to save the preferences ("Save state"). There is some other way/event to detect that the user changed the state of the table (in order, to me to save and avoid to force the user to click on a button for that)?
I was hopping to find some method here but i didn't..
I initially had code that listened to all of the applicable events from the grid, but ultimately, I found it easier to just save the entire grid state in the component's onDestroy method, regardless of whether anything has actually changed.
Found my answer here.
All the events are here but i prefer to add a global event:
addGlobalListener(listener) Add an event listener for all event types coming from the grid.)
Source: AgGrid javascript grid api

MFC: Best place to prevent a window from re-appearing from a Restore operation

When my application is minimized, and the application programmatically closes a child window, the state of the child window between my framework and MFC goes out of sync because MFC will not send a WM_SHOWWINDOW message when the application is minimized. I noticed that Qt had the same problem: https://codereview.qt-project.org/#/c/93410/
Things that I have tried:
Override OnShowWindow() -- if the states are out of sync, then I alter the BOOL parameter before passing it to the CDialog::OnShowWindow. But doing so does nothing. It is as if the BOOL parameter given to the override is read-only.
Handle WM_SHOWWINDOW in PreTranslateMessage -- this does not work because WM_SHOWWINDOW does not appear here.
I know I can check SW_PARENTOPENING to know when to look for out-of-sync problems and handle it, but I just don't know where is the best place to do it.
My current solution is to override OnShowWindow, check for SW_PARENTOPENING, then post a SW_HIDE. It works, but it feels like a waste because I should be able to prevent it from restoring entirely rather than defer it.
Summary:
Basically, I am just programmatically closing a window, say from a timer call, or user's remote command, or whatever, while the main application is minimized. The dialog will be temporarily hidden when minimized (the MFC framework will automatically call ShowWindow(SW_HIDE) but with an internal flag to re-open when the app is restored). If my program sends ShowWindow(SW_HIDE) now, this call will not be registered, and the window will be re-opened by MFC when the app is maximized. To my user, he/she has closed the window remotely and does not expect the window to re-appear, so I need to re-call my ignored ShowWindow(SW_HIDE) somehow when restoring the main app.

A blocking but non-modal QDialog?

I have a stack of images on which I want to perform some operations. After processing each image, my program should pop up a dialog to prompt the user if they want to proceed with the next image or to abort. Before that, they should have an opportunity to do some manual changes either on the images or on the parameters. Anyway, they must have access to the windows of the applications, while the execution of the method that called the dialog should be blocked until the dialog is closed.
I tried to solve this with a QMessageBox, but if I open it via exec(), it blocks the entire application, and if I use show(), the execution of the program goes on without waiting for user's reaction.
Is there a convenient way to block the calling method or function with a dialog but permit the user to interact with other windows?
Thanks in advance for any hint.
You should split your method that you want to block into two parts. In the end of first part you need to show your dialog without blocking and connect "Next" button (for example) of the dialog to the slot that must contains second part of your old method. This slot will be executed only when user presses the button.
It's the right way to do it in Qt. You need posibly to change your code logic to implement this.
Also, do you really need the second dialog? You can place "Next" button to your main widget. You can also create another modal dialog that will contain some settings and "Next" button.

How can you be notified when the user switches between views?

In an MDI application, when the user switches between views something has to be updated. What's the best message to handle for realizing when this happens?
In my application a document has only one view, but logically I want to get notified when switch is between documents.
You can catch WM_SETFOCUS in CChildFrame (ChildFrm.h). When a user clicks a view window, or sets focus to a view in another manner, this member function can be a bridge to whatever you need to set in the application.

Disabling Save Button when Validation Errors Occur In An Eclipse-RAP Application

We are using Eclipse API in our RAP application.This uses Eclipse Modeling Frame Work.
When a page gets edited, Model Becomes Dirty and as a Result,Save Button gets Enabled.
In our editor pages, when ever there is an error in the Page, we set the Validation flag of the Editor page to false, which would in turn display red colored marks on the page.Then usually save button is also becoming enabled.
But, I want to change this behavior.When some error mark appears on the page, I don't want to get the save button enabled,.It shouldn't allow the user to save the model in the error stage.
The save button should be disabled, How can I achieve this.
Kindly clear my doubt.
The editor generated by EMF uses a commandstacklistener to fire a PROP_DIRTY to the editor. If this property is fired, the underlying framework will ask the editors #isDirty Method for the dirty state. This is the place where you can implement your logic.
#Override
public boolean isDirty() {
Diagnostic diagnostic = validateMyModel();
return ((BasicCommandStack)editingDomain.getCommandStack()).isSaveNeeded() && diagnostic.getSeverity() == Diagnostic.OK;
}
This case doesn't cover the usecase, that the editor could have been already dirty when the user makes a not-valid edit on the model.
But that is not the best way IMHO. Because if the user closes the editor all changes of the model are lost, without any notification (because of the missing dirty-flag). So he probably did 100 valid modifications, 1 invalid and loses his changed model.
A better way is to show a warning-message if the user wants to save the dialog. If there are errors in the dialog the editor cannot change its state from dirty to not-dirty and the user has to
correct all erros or
close the editor and looses all his changens
To achieve that you have to implement in your doSave(IProgressMonitor progressMonitor) method a dialog to show the errors. The more tricky part is to override the default-behavior of closing a dirty editor. The workbench will show a dialog with, Yes, No and Cancel
To override this behavior you have to implement the interface org.eclipse.ui.ISaveablePart2 in your editor to override the promptToSaveOnClose() method. In this method there must be again your logic that checks for errors in the model. If there are errors, this method has to return ISaveablePart2.CANCEL so that editor is not closable as long as there are errors in the dirty model.
HTH Tom