1 /*******************************************************************
2 
3 Part of the Fritzing project - http://fritzing.org
4 Copyright (c) 2007-2014 Fachhochschule Potsdam - http://fh-potsdam.de
5 
6 Fritzing 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, either version 3 of the License, or
9 (at your option) any later version.
10 
11 Fritzing is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 GNU General Public License for more details.
15 
16 You should have received a copy of the GNU General Public License
17 along with Fritzing.  If not, see <http://www.gnu.org/licenses/>.
18 
19 ********************************************************************
20 
21 $Revision: 6904 $:
22 $Author: irascibl@gmail.com $:
23 $Date: 2013-02-26 16:26:03 +0100 (Di, 26. Feb 2013) $
24 
25 ********************************************************************/
26 
27 #include "waitpushundostack.h"
28 #include "utils/misc.h"
29 #include "utils/folderutils.h"
30 #include "commands.h"
31 
32 #include <QCoreApplication>
33 #include <QTextStream>
34 
CommandTimer(QUndoCommand * command,int delayMS,WaitPushUndoStack * undoStack)35 CommandTimer::CommandTimer(QUndoCommand * command, int delayMS, WaitPushUndoStack * undoStack) : QTimer()
36 {
37 	m_undoStack = undoStack;
38 	m_command = command;
39 	m_undoStack->addTimer(this);
40 	setSingleShot(true);
41 	setInterval(delayMS);
42 	connect(this, SIGNAL(timeout()), this, SLOT(timedout()));
43 	start();
44 }
45 
timedout()46 void CommandTimer::timedout() {
47     if (m_undoStack) {
48 	    m_undoStack->push(m_command);
49 	    m_undoStack->deleteTimer(this);
50     }
51 }
52 
53 /////////////////////////////////
54 
WaitPushUndoStack(QObject * parent)55 WaitPushUndoStack::WaitPushUndoStack(QObject * parent) :
56 	QUndoStack(parent)
57 {
58     m_temporary = NULL;
59 #ifndef QT_NO_DEBUG
60     QString path = FolderUtils::getUserDataStorePath("");
61     path += "/undostack.txt";
62 
63 	m_file.setFileName(path);
64 	m_file.remove();
65 #endif
66 }
67 
~WaitPushUndoStack()68 WaitPushUndoStack::~WaitPushUndoStack() {
69     clearLiveTimers();
70     clearDeadTimers();
71 }
72 
push(QUndoCommand * cmd)73 void WaitPushUndoStack::push(QUndoCommand * cmd)
74 {
75 #ifndef QT_NO_DEBUG
76 	writeUndo(cmd, 0, NULL);
77 #endif
78     if (m_temporary == cmd) {
79         m_temporary->redo();
80         return;
81     }
82 
83 	QUndoStack::push(cmd);
84 }
85 
86 
waitPush(QUndoCommand * command,int delayMS)87 void WaitPushUndoStack::waitPush(QUndoCommand * command, int delayMS) {
88 	clearDeadTimers();
89     if (delayMS <= 0) {
90         push(command);
91         return;
92     }
93 
94 	new CommandTimer(command, delayMS, this);
95 }
96 
97 
waitPushTemporary(QUndoCommand * command,int delayMS)98 void WaitPushUndoStack::waitPushTemporary(QUndoCommand * command, int delayMS) {
99     m_temporary = command;
100 	waitPush(command, delayMS);
101 }
102 
clearDeadTimers()103 void WaitPushUndoStack::clearDeadTimers() {
104     clearTimers(m_deadTimers);
105 }
106 
clearLiveTimers()107 void WaitPushUndoStack::clearLiveTimers() {
108     clearTimers(m_liveTimers);
109 }
110 
clearTimers(QList<QTimer * > & timers)111 void WaitPushUndoStack::clearTimers(QList<QTimer *> & timers) {
112 	QMutexLocker locker(&m_mutex);
113 	foreach (QTimer * timer, timers) {
114 		delete timer;
115 	}
116 	timers.clear();
117 }
118 
deleteTimer(QTimer * timer)119 void WaitPushUndoStack::deleteTimer(QTimer * timer) {
120 	QMutexLocker locker(&m_mutex);
121 	m_deadTimers.append(timer);
122 	m_liveTimers.removeOne(timer);
123 }
124 
addTimer(QTimer * timer)125 void WaitPushUndoStack::addTimer(QTimer * timer) {
126 	QMutexLocker locker(&m_mutex);
127 	m_liveTimers.append(timer);
128 }
129 
hasTimers()130 bool WaitPushUndoStack::hasTimers() {
131 	QMutexLocker locker(&m_mutex);
132 	return m_liveTimers.count() > 0;
133 }
134 
resolveTemporary()135 void WaitPushUndoStack::resolveTemporary() {
136     TemporaryCommand * tc = dynamic_cast<TemporaryCommand *>(m_temporary);
137     m_temporary = NULL;
138     if (tc) {
139         tc->setEnabled(false);
140         push(tc);
141         tc->setEnabled(true);
142     }
143 }
144 
deleteTemporary()145 void WaitPushUndoStack::deleteTemporary() {
146     if (m_temporary != NULL) {
147         delete m_temporary;
148         m_temporary = NULL;
149     }
150 }
151 
152 #ifndef QT_NO_DEBUG
writeUndo(const QUndoCommand * cmd,int indent,const BaseCommand * parent)153 void WaitPushUndoStack::writeUndo(const QUndoCommand * cmd, int indent, const BaseCommand * parent)
154 {
155 	const BaseCommand * bcmd = dynamic_cast<const BaseCommand *>(cmd);
156 	QString cmdString;
157 	QString indexString;
158 	if (bcmd == NULL) {
159 		cmdString = cmd->text();
160 	}
161 	else {
162 		cmdString = bcmd->getDebugString();
163 		indexString = QString::number(bcmd->index()) + " ";
164 	}
165 
166    	if (m_file.open(QIODevice::Append | QIODevice::Text)) {
167    		QTextStream out(&m_file);
168 		QString indentString(indent, QChar(' '));
169 		if (parent) {
170 			indentString += QString("(%1) ").arg(parent->index());
171 		}
172 		indentString += indexString;
173 		out << indentString << cmdString << "\n";
174 		m_file.close();
175 	}
176 
177 	for (int i = 0; i < cmd->childCount(); i++) {
178 		writeUndo(cmd->child(i), indent + 4, NULL);
179 	}
180 
181 	if (bcmd) {
182 		for (int i = 0; i < bcmd->subCommandCount(); i++) {
183 			writeUndo(bcmd->subCommand(i), indent + 4, bcmd);
184 		}
185 	}
186 }
187 #endif
188 
189