Aborting undo command in an undo stack - c++

I'm calling an undo command from within QML:
cppClass.undoHandler.createCommand(option)
The C++ undo-handler pushes undo command into undo stack:
void UndoHandler::createCommand(
const QString & option
)
{
m_undoStack->push(new Command(
option
));
}
The actual C++ undo command is:
class Command : public QUndoCommand
{
// ...
virtual void undo();
virtual void redo();
// ...
Logic *m_logic;
}
void Command::redo()
{
m_outputName = m_logic->run(m_option);
}
And the logic runs like this:
QString Logic::run(const QString option)
{
if ( /* some condition here */ ) {
// ** What I want to achieve:
// If this condition is met
// abort the current undo-command
// I mean pop the current undo-command which is already pushed into stack
}
}
How can I abort/pop/break the undo-command by the above condition inside the logic? I'm not sure how it should be designed, any idea?

You can use QUndoCommand::setObsolete() and make the command obsolete.
The boolean is used for the automatic removal of commands that are not necessary in the stack anymore. The isObsolete function is checked in the functions QUndoStack::push(), QUndoStack::undo(), QUndoStack::redo(), and QUndoStack::setIndex().

I used the if condition before pushing undo command into stack like this:
void UndoHandler::createCommand(
const QString & option
)
{
Command *command = new Command(option);
// Check validity before pushing undo command into undo stack
bool isValid = command->doubleCheck();
if (isValid) {
m_undoStack->push(command);
} else {
delete command;
}
}
Undo command has a new method to check the if condition:
class Command : public QUndoCommand
{
// ...
virtual void undo();
virtual void redo();
// ...
// New method to check validity
bool doubleCheck();
// ...
Logic *m_logic;
const QString m_option;
}
bool Command::doubleCheck() {
return m_logic->doubleCheck(m_option);
}
void Command::redo()
{
// Redo method has to be modified accordingly
}
The if condition is inside a separate method in logic:
bool Logic::doubleCheck(const QString option)
{
if ( /* some condition here */ )
return true;
else
return false;
}

Related

Object property sibling access

I'm making a game with a debugging console. It is structured like:
class Game
{
bool debugMode;
// ...
std::unique_ptr<Loop> loop;
std::unique_ptr<Debugger> debugger;
// ...
}
It works great in the class functions:
void Game::init()
{
// ...
loop = std::make_unique<Loop>();
if (debugMode)
{
debugger = std::make_unique<Debugger>();
debugger->console->write(L"Game initialized."); // works great!
}
}
But what if I want to write something to the console in loop?
I don't want to pass debugger to loop.
I don't want to create
another debugger in loop.
How do I give loop access to debugger?
Use a shared_ptr as suggested by Sam Varshavchik.
Several shared_ptr objects may own the same object.1
This is now I got it to work, in case your interested:
class Game
{
bool debugMode;
// ...
std::unique_ptr<Loop> loop;
std::shared_ptr<Debugger> debugger;
// ...
}
The init function:
void Game::init()
{
// ...
if (debugMode)
{
debugger = std::make_unique<Debugger>();
loop = std::make_unique<Loop>(debugger);
debugger->console->write(L"Game initialized."); // works great!
}
else
{
loop = std::make_unique<Loop>();
}
}
The Loop constructor:
Loop::Loop(std::shared_ptr<Debugger> debugger) : Loop()
{
this->debugger = debugger;
}

Checkbox change other checkbox statement

I need to connect some Checkboxes, so when I click one it becomes checked and other become unchecked. My code right now looks like this.
Connect in class constructor:
connect(cb_thickness1,SIGNAL(stateChanged(int)),this,SLOT(cb_thickness1_isChecked()));
connect(cb_thickness2,SIGNAL(stateChanged(int)),this,SLOT(cb_thickness2_isChecked()));
connect(cb_thickness3,SIGNAL(stateChanged(int)),this,SLOT(cb_thickness3_isChecked()));
and slots
void MainWind::cb_thickness1_isChecked()
{
if(cb_thickness2->isChecked())
cb_thickness2->setChecked(false);
if(cb_thickness3->isChecked())
cb_thickness3->setChecked(false);
}
void MainWind::cb_thickness2_isChecked()
{
if(cb_thickness1->isChecked())
cb_thickness1->setChecked(false);
if(cb_thickness3->isChecked())
cb_thickness3->setChecked(false);
}
void MainWind::cb_thickness3_isChecked()
{
if(cb_thickness1->isChecked())
cb_thickness1->setChecked(false);
if(cb_thickness2->isChecked())
cb_thickness2->setChecked(false);
}
Code doesn't work as expected. When I click to any ChBx first time, everything is OK, but when I click to other next time it only uncheck previous and does nothing with itself. Only on second click it become chekced.
Also I found one more bug, when I check to ChBox, and then uncheck it by clicking it againg, I can check 2 ChBxes. [pic 2]
Radio button is a great idea.
But if you really want to use check box, you can explicitly set cb_thickness1 checked in cb_thickness1_isChecked(), and do the same for other two check boxes.
void MainWind::cb_thickness1_isChecked()
{
cb_thickness1->setChecked(true);
cb_thickness2->setChecked(false);
cb_thickness3->setChecked(false);
}
void MainWind::cb_thickness2_isChecked()
{
cb_thickness1->setChecked(false);
cb_thickness2->setChecked(true);
cb_thickness3->setChecked(false);
}
void MainWind::cb_thickness3_isChecked()
{
cb_thickness1->setChecked(false);
cb_thickness2->setChecked(false);
cb_thickness3->setChecked(true);
}
I suggest to derive a class from QCheckBox (lets call it CustomCheckBox) and add a signal, private slot and public slot
signal:
void enabled();
private slot:
void CustomCheckBox::checkEnable(bool state)
{
if(state)
{
emit enabled();
}
}
public slot:
void CustomCheckBox::uncheck()
{
setChecked(false);
}
In the constructor add:
connect(this,SIGNAL(toggled(bool)),this,SLOT(checkEnable(bool)));
This way you can use simple connects.
CustomCheckBox *box1 = new CustomCheckBox();
CustomCheckBox *box2 = new CustomCheckBox();
connect(box1,SIGNAL(enabled()),box2,SLOT(uncheck()));
Feel free to improve this answer. :)
Verify that the state of the button is checked in the slot and then deactivate the other checkboxes like you already did. You can use the parameter of the stateChanged method by passing it to the slots.
Here is code that works:
Variant I:
connect(ui->checkBoxA, SIGNAL(stateChanged(int)), this, SLOT(checkBoxAChanged(int)));
connect(ui->checkBoxB, SIGNAL(stateChanged(int)), this, SLOT(checkBoxBChanged(int)));
connect(ui->checkBoxC, SIGNAL(stateChanged(int)), this, SLOT(checkBoxCChanged(int)));
void MainWindow::checkBoxAChanged(int state)
{
if (state == Qt::Checked) {
ui->checkBoxB->setChecked(false);
ui->checkBoxC->setChecked(false);
}
}
void MainWindow::checkBoxBChanged(int state)
{
if (state == Qt::Checked) {
ui->checkBoxA->setChecked(false);
ui->checkBoxC->setChecked(false);
}
}
void MainWindow::checkBoxCChanged(int state)
{
if (state == Qt::Checked) {
ui->checkBoxB->setChecked(false);
ui->checkBoxA->setChecked(false);
}
}
Variant II:
connect(ui->checkBoxA, SIGNAL(clicked(bool)), this, SLOT(checkBoxAClicked(bool)));
connect(ui->checkBoxB, SIGNAL(clicked(bool)), this, SLOT(checkBoxBClicked(bool)));
connect(ui->checkBoxC, SIGNAL(clicked(bool)), this, SLOT(checkBoxCClicked(bool)));
void MainWindow::checkBoxAClicked(bool val)
{
if (val == true) {
ui->checkBoxB->setChecked(false);
ui->checkBoxC->setChecked(false);
}
}
void MainWindow::checkBoxBClicked(bool val)
{
if (val == true) {
ui->checkBoxA->setChecked(false);
ui->checkBoxC->setChecked(false);
}
}
void MainWindow::checkBoxCClicked(bool val)
{
if (val == true) {
ui->checkBoxB->setChecked(false);
ui->checkBoxA->setChecked(false);
}
}

How to check two QLineEdit If they are not empty

I have three controls, two QTextLine and one QPushButton.
When startup the program, the add button will be disabled, and must be two QTextLine not empty for enable the add button.
I have the following code, but it does not works fine:
void Question_Answer::on_newQuestion_txt_textChanged(const QString &arg1)
{
if(arg1.isEmpty())
{
ui->addNewQuestion_btn->setEnabled(false);
}
else
{
ui->addNewQuestion_btn->setEnabled(true);
}
}
void Question_Answer::on_newAnswer_txt_textChanged(const QString &arg1)
{
if(ui->newAnswer_txt->text().isEmpty())
{
ui->addNewQuestion_btn->setEnabled(false);
}
else
{
ui->addNewQuestion_btn->setEnabled(true);
}
}
Now, How to check if the two QTextLine are not empty, and also if any of them is empty, how to disable the add button.
Just connect a single slot to handle textChanged signals of both LineEdits
void Question_Answer::onTextChanged(const QString &arg1){
if(ui->newAnswer_txt->text().isEmpty() || ui->newQuestion_txt->text().isEmpty()){
ui->addNewQuestion_btn->setEnabled(false);
}else{
ui->addNewQuestion_btn->setEnabled(true);
}
}
In the header class:
// ...
private slots:
void onTextChanged();
// ...
In the source file:
// Setup the connections in the constructor.
void Question_Answer::onTextChanged()
{
const bool editable1 = ui->newAnswer_txt->text().size() > 0;
const bool editable2 = ui->newQuestion_txt->text().size() > 0;
ui->addNewQuestion_btn->setEnabled( editable1 && editable2 );
}

Undo stack remains empty in Qt

I am trying to undo/redo in multi document interface. I have different entities. Each entity has its own class. I have used UndoGroup but when I unable to push them to undoStack dont know whats's wrong there. Can anyone help me to solve the issue.
cadgraphicscene.cpp
CadGraphicsView::CadGraphicsView()
{
undoStack = new QUndoStack(this);
}
QUndoStack *CadGraphicsView::m_undoStack() const
{
return undoStack;
}
void CadGraphicsView::showUndoStack()
{
undoView = 0;
// shows the undoStack window
if (undoView == 0)
{
undoView = new QUndoView(undoStack);
undoView->setWindowTitle("Undo Stack");
}
undoView->show();
}
mainwindow.cpp
MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent)
{
m_undoGroup = new QUndoGroup(this);
QAction *undoAction = m_undoGroup->createUndoAction(this);
undoAction->setShortcut(QKeySequence::Undo);
QAction *redoAction = m_undoGroup->createRedoAction(this);
redoAction->setShortcut(QKeySequence::Redo);
menuEdit->insertAction(menuEdit->actions().at(1), undoAction);
menuEdit->insertAction(undoAction, redoAction);
menuEdit->addAction(undoAction);
menuEdit->addAction(redoAction);
undoAction->setEnabled(true);
redoAction->setEnabled(true);
}
void MainWindow::updateActions()
{
CadGraphicsView *view = currentDocument();
m_undoGroup->setActiveStack(view == 0 ? 0 : view->m_undoStack());
}
void MainWindow::addDocument(CadGraphicsView *view)
{
m_undoGroup->addStack(view->m_undoStack());
connect(view->m_undoStack(), SIGNAL(indexChanged(int)), this, SLOT(updateActions()));
connect(view->m_undoStack(), SIGNAL(cleanChanged(bool)), this, SLOT(updateActions()));
setCurrentDocument(view);
}
void MainWindow::setCurrentDocument(CadGraphicsView *view)
{
mdiArea->currentSubWindow();
}
CadGraphicsView *MainWindow::currentDocument() const
{
return qobject_cast<CadGraphicsView *>(mdiArea->parentWidget());
}
I am confused with why I am not able to push entities to undoStack. Please help me to solve this issue
I think the problem is in these two functions (see the inline comments):
void MainWindow::setCurrentDocument(CadGraphicsView *view)
{
// The view argument is not used at all. You do not set anything here.
mdiArea->currentSubWindow();
}
CadGraphicsView *MainWindow::currentDocument() const
{
// mdiArea->parentWidget() returns the MainWindow, so this function
// always returns 0.
return qobject_cast<CadGraphicsView *>(mdiArea->parentWidget());
// You should write it as
// return qobject_cast<CadGraphicsView *>(mdiArea->activeSubWindow()->widget());
}

Google Glass GDK CameraManager Intent

Does anyone know if when you use the GDK Cameramanager Intent to take a picture, is there a way to not show the preview or close it automatically? Capturing an image for use in app and don't want to have to tap to accept.
I probably have missed something.
Thanks,
You can try this:
Intent localIntent = new Intent("com.google.glass.action.TAKE_PICTURE_FROM_SCREEN_OFF");
localIntent.putExtra("should_finish_turn_screen_off", true);
localIntent.putExtra("should_take_picture", true);
localIntent.putExtra("screenshot_file_path", pathToFile);
startActivity(localIntent);
It will close your preview automatically after few seconds.
try this...
private void takePicture() {
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
startActivityForResult(intent, 0);
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == 0 && resultCode == RESULT_OK) {
String picturePath=data.getStringExtra(CameraManager.EXTRA_PICTURE_FILE_PATH);
processPictureWhenReady(picturePath);
}
super.onActivityResult(requestCode, resultCode, data);
}
private void processPictureWhenReady(final String picturePath) {
final File pictureFile = new File(picturePath);
if (pictureFile.exists()) {
// The picture is ready; process it.
// Write your code here
} else {
final File parentDirectory = pictureFile.getParentFile();
FileObserver observer = new FileObserver(parentDirectory.getPath()) {
// Protect against additional pending events after CLOSE_WRITE is
// handled.
private boolean isFileWritten;
#Override
public void onEvent(int event, String path) {
if (!isFileWritten) {
// For safety, make sure that the file that was created in
// the directory is actually the one that we're expecting.
File affectedFile = new File(parentDirectory, path);
isFileWritten = (event == FileObserver.CLOSE_WRITE
&& affectedFile.equals(pictureFile));
if (isFileWritten) {
stopWatching();
// Now that the file is ready, recursively call
// processPictureWhenReady again (on the UI thread).
runOnUiThread(new Runnable() {
#Override
public void run() {
processPictureWhenReady(picturePath);
}
});
}
}
}};
observer.startWatching();
}
}