QStringList ChecksumTask::m_checksumInfo;
bool ChecksumTask::m_sourceProcessingReady = false;
-
+static const int MAX_INDEX = 0x7fff;
/**
* Constructor.
*
*
* @param directory directory to inspect, e.g. "/media/trg/x"
* @param maxAge all files older than this time point will be deleted
- * @param index the index in the shadow directories
*/
-void BackupEngine::removeOlder(const QString& directory, const QDateTime& time,
- int index){
+void BackupEngine::removeOlder(const QString& directory, const QDateTime& time){
QDirIterator it(directory);
QString info, node;
- int lengthBase = m_shadowDirs.at(index).length();
- assert(index < 0x7fff);
- QString prefix;
m_mutex.lock();
m_totalDirs++;
m_mutex.unlock();
node = it.fileName();
if (it.fileInfo().isDir()){
if (node != "." && node != ".."){
- removeOlder(it.filePath(), time, index);
+ removeOlder(it.filePath(), time);
isEmpty = false;
}
} else if (it.fileInfo().lastModified() < time){
isEmpty = false;
- info = QChar(index + 1) + it.filePath() + m_separatorString
- + QChar(CmdRemove) ;
+ info = QChar(MAX_INDEX) + it.filePath() + m_separatorString
+ + QChar(CmdRemove);
m_mutex.lock();
m_files.append(info);
m_hotFiles++;
}
}
if (isEmpty){
- info = QChar(index + 1) + it.filePath() + m_separatorString
+ info = QChar(MAX_INDEX) + it.filePath() + m_separatorString
+ QChar(CmdRemoveDir);
m_mutex.lock();
m_files.append(info);
{
QString relPath, node;
QString info;
- qint64 start = QDateTime::currentMSecsSinceEpoch();
- while (true){
+ QDateTime start = QDateTime::currentDateTime();
+ while (! m_shouldStop){
m_mutex.lock();
if (m_files.size() == 0)
info.clear();
relPath = info.mid(1, pos - 1);
node = info.mid(pos + 1);
copyFile(index, relPath, node);
- qint64 now = QDateTime::currentMSecsSinceEpoch();
- qint64 estimated = qint64(double(now - start) / max(1LL, m_processedBytes) * m_hotBytes);
+ qint64 duration = QDateTime::currentMSecsSinceEpoch() - start.currentMSecsSinceEpoch();
+ double factor = double(m_hotBytes) / max(1LL, m_processedBytes);
m_mainWindow->externalAppend(ReGuiQueueItem::StatusLine, NULL,
- tr("%1 of %2 (%3 of %4) %5 MB/sec Remaining: %6 of %7")
+ tr("%1 of %2 (%3 of %4) %5 MB/sec runtime: %6")
.arg(m_processedFiles).arg(m_hotFiles)
- .arg(ReQStringUtils::readableSize(m_processedBytes))
- .arg(ReQStringUtils::readableSize(m_hotBytes))
- .arg(m_processedBytes / 1024.0 / 1024 / (now - start) * 1000, 0, 'f', 3)
- .arg(ReQStringUtils::readableDuration(estimated - (now - start)))
- .arg(ReQStringUtils::readableDuration(estimated)));
+ .arg(ReQStringUtils::readableSize(m_processedBytes))
+ .arg(ReQStringUtils::readableSize(m_hotBytes))
+ .arg(m_processedBytes / 1024.0 / 1024 * 1000 / max(1LL, duration), 0, 'f', 3)
+ .arg(ReQStringUtils::runtimeEstimation(start, factor)));
}
}
m_mainWindow->externalTaskFinished(tr("backup complete after %1. Errors: %2")
.arg(ReQStringUtils::readableDuration(
- QDateTime::currentMSecsSinceEpoch() - start))
+ QDateTime::currentMSecsSinceEpoch() - start.currentMSecsSinceEpoch()))
.arg(m_mainWindow->errors()));
}
QString relPath, node;
QString info;
int count = 0;
- while (true){
+ while (! m_shouldStop){
m_mutex.lock();
if (m_files.size() == 0)
info.clear();
*/
void ChecksumOfTargetTask::run()
{
- qint64 start = QDateTime::currentMSecsSinceEpoch();
+ QDateTime start = QDateTime::currentDateTime();
QString relPath, node;
qint64 now = 0;
QString info;
int count = 0;
- while (true){
+ while (! m_shouldStop){
m_mutex.lock();
if (m_checksumInfo.size() == 0)
info.clear();
processedFiles = m_processedFiles;
m_mutex.unlock();
now = QDateTime::currentMSecsSinceEpoch();
- double duration = (now - start);
- double estimated = qint64(double(now - start));
- estimated /= max(1LL, m_processedBytes);
- estimated *= m_hotBytes * 2;
- qint64 rest = qint64(estimated - duration);
+ qint64 duration = (now - start.currentMSecsSinceEpoch());
+ double factor = double(m_hotBytes) * 2 / max(1LL, m_processedBytes);
m_mainWindow->externalAppend(ReGuiQueueItem::StatusLine, NULL,
- tr("%1 of %2 (%3 of %4) %5 MB/sec Remaining: %6 of %7")
+ tr("%1 of %2 (%3 of %4) %5 MB/sec runtime: %6")
.arg(processedFiles).arg(hotFiles * 2)
.arg(ReQStringUtils::readableSize(processedBytes))
.arg(ReQStringUtils::readableSize(hotBytes * 2))
- .arg(processedBytes / 1024.0 / 1024 / duration * 1000.0, 0, 'f', 3)
- .arg(ReQStringUtils::readableDuration(rest))
- .arg(ReQStringUtils::readableDuration(qint64(estimated))));
+ .arg(processedBytes / 1024.0 / 1024 / max(1LL, duration) * 1000.0, 0, 'f', 3)
+ .arg(ReQStringUtils::runtimeEstimation(start, factor)));
}
}
now = QDateTime::currentMSecsSinceEpoch();
m_mainWindow->externalTaskFinished(tr("Building target checksums complete after %1. Processed: %2 Errors: %3")
- .arg(ReQStringUtils::readableDuration(now - start))
+ .arg(ReQStringUtils::readableDuration(now - start.currentMSecsSinceEpoch()))
.arg(count)
.arg(m_mainWindow->errors()));
}
{
QString relPath, node;
QString info;
- qint64 start = QDateTime::currentMSecsSinceEpoch();
- while (true){
+ QDateTime start = QDateTime::currentDateTime();
+ while (! m_shouldStop){
m_mutex.lock();
if (m_files.size() == 0)
info.clear();
break;
case CmdMove:
{
+ assert(index < MAX_INDEX);
QString target = m_targetDirs.at(index) + relPath + node;
QString shadowDir = m_shadowDirs.at(index) + relPath;
ReQStringUtils::chomp(shadowDir, OS_SEPARATOR);
error("unknown command: " + QString::number(command));
break;
}
- qint64 now = QDateTime::currentMSecsSinceEpoch();
- qint64 estimated = qint64(double(now - start) / max(1, m_processedFiles) * m_hotFiles);
+ double factor = double(m_hotFiles) / max(1, m_processedFiles);
+ qint64 duration = QDateTime::currentMSecsSinceEpoch() - start.currentMSecsSinceEpoch();
m_mainWindow->externalAppend(ReGuiQueueItem::StatusLine, NULL,
- tr("%1 of %2 (%3 of %4) %5 MB/sec Remaining: %6 of %7")
- .arg(m_processedFiles).arg(m_hotFiles)
- .arg(ReQStringUtils::readableSize(m_processedBytes))
- .arg(ReQStringUtils::readableSize(m_hotBytes))
- .arg(m_processedBytes / 1024.0 / 1024 / (now - start) * 1000, 0, 'f', 3)
- .arg(ReQStringUtils::readableDuration(estimated - (now - start)))
- .arg(ReQStringUtils::readableDuration(estimated)));
+ tr("%1 of %2 (%3 of %4) %5 MB/sec runtime: %6")
+ .arg(m_processedFiles)
+ .arg(m_hotFiles)
+ .arg(ReQStringUtils::readableSize(m_processedBytes))
+ .arg(ReQStringUtils::readableSize(m_hotBytes))
+ .arg(m_processedBytes / 1024.0 / 1024 * 1000
+ / max(1.0, (double) duration), 0, 'f', 3)
+ .arg(ReQStringUtils::runtimeEstimation(start, factor)));
}
}
m_mainWindow->externalTaskFinished(tr("backup complete after %1. Errors: %2")
.arg(ReQStringUtils::readableDuration(
- QDateTime::currentMSecsSinceEpoch() - start))
+ QDateTime::currentMSecsSinceEpoch() - start.currentMSecsSinceEpoch()))
.arg(m_mainWindow->errors()));
}
qint64 start = QDateTime::currentMSecsSinceEpoch();
m_searchReady = false;
QString targetDir, sourceDir;
- for (int ix = 0; ix < m_sourceDirs.size(); ix++){
+ for (int ix = 0; ! m_shouldStop && ix < m_sourceDirs.size(); ix++){
sourceDir = m_sourceDirs.at(ix);
if (m_compareWithTarget)
targetDir = m_targetDirs.at(ix) + ReFileUtils::nodeOf(sourceDir);
QDirIterator it(source);
QString info, node;
int lengthBase = m_sourceDirs.at(index).length();
- assert(index < 0x7fff);
+ assert(index < MAX_INDEX);
QString prefix;
m_mutex.lock();
m_totalDirs++;
QDirIterator it(target);
QString info, node, relPath;
int lengthBase = m_targetDirs.at(index).length();
- assert(index < 0x7fff);
+ assert(index < MAX_INDEX);
QString prefix;
m_mutex.lock();
m_totalDirs++;
error(QObject::tr("cannot move to shadow directory (%1): %2 -> %3")
.arg(errno).arg(target).arg(shadow));
} else {
- removeOlder(shadow, m_maxAge, index);
+ removeOlder(shadow, m_maxAge);
}
}
}
qint64 start = QDateTime::currentMSecsSinceEpoch();
m_searchReady = false;
QString targetDir, sourceDir;
- for (int ix = 0; ix < m_sourceDirs.size(); ix++){
+ for (int ix = 0; ! m_shouldStop && ix < m_sourceDirs.size(); ix++){
sourceDir = m_sourceDirs.at(ix);
targetDir = m_targetDirs.at(ix);
searchOneDirectory(targetDir, sourceDir, ix);
}
+ if (! m_shouldStop){
+ removeOlder(m_shadowBaseDir, m_maxAge);
+ }
m_searchReady = true;
m_mainWindow->externalLog(tr(
"Search in target finished: to process: %1 with %2 dirs to delete: %3 total: %4 "
bool log(const QString& message);
protected:
void initializeShadowDir();
- void removeOlder(const QString& directory, const QDateTime& time, int index);
+ void removeOlder(const QString& directory, const QDateTime& time);
virtual void run() = 0;
protected:
// list of source dirs, trailing with separator
target->setItem(row, base + 1, new QTableWidgetItem(item.m_target));
target->setItem(row, base + 2, new QTableWidgetItem(! item.m_lastBackup.isValid() ? "" :
BackupUtils::dateToString(item.m_lastBackup)));
- target->setItem(row, base + 3, new QTableWidgetItem(item.m_sources.join(" ")));
+ target->setItem(row, base + 3, new QTableWidgetItem(item.m_sources.join(";")));
}
}
connect(ui->pushButtonClearEdit, SIGNAL(clicked()), this, SLOT(onClearEdit()));
connect(ui->pushButtonClearList, SIGNAL(clicked()), this, SLOT(onClearList()));
connect(ui->pushButtonSave, SIGNAL(clicked()), this, SLOT(onSave()));
+ connect(ui->pushButtonInterpolate, SIGNAL(clicked()), this, SLOT(onInterpolate()));
+ connect(ui->pushButtonExpand, SIGNAL(clicked()), this, SLOT(onExpand()));
onLoad();
}
*/
void MainWindow::onClearEdit()
{
- ui->textEditResult->setText("");
+ ui->plainTextEditResult->setPlainText("");
}
/**
ui->listWidgetResult->clear();
}
+/**
+ * Copies the input buffer n times and replaces the placeholder with values.
+ *
+ * The values are taken from the values buffer.
+ */
+void MainWindow::onExpand()
+{
+ QString var = ui->lineEditVariable->text();
+ if (var.isEmpty())
+ say(LOG_ERROR, "cannot expand: no variable given");
+ else {
+ QString block = ui->plainTextEditInput->toPlainText();
+ QString vals = ui->plainTextEditValues->toPlainText();
+ QStringList values = vals.split('\n');
+ QString result;
+ result.reserve(block.length() * values.count() + vals.length());
+ for (int ix = 0; ix < values.count(); ix++){
+ result += QString(block).replace(var, values.at(ix));
+ }
+ ui->plainTextEditResult->setPlainText(result);
+ }
+}
+
/**
* Set GUI elements from the queue when the GUI timer is triggered.
*/
}
}
+/**
+ * Interpolates the range into the values buffer.
+ */
+void MainWindow::onInterpolate()
+{
+ QString range = ui->lineEditRange->text();
+ QRegularExpression regExpr("^(\\d+)-(\\d+)(,(\\d+))?$");
+ QRegularExpressionMatch match = regExpr.match(range);
+ QString lines;
+ if (match.hasMatch()){
+ int from = match.captured(1).toInt();
+ int to = match.captured(2).toInt();
+ int step = match.captured(3).isEmpty() ? 1 : match.captured(4).toInt();
+ for (int ix = from; ix <= to; ix += step){
+ lines += QString::number(ix) + "\n";
+ }
+ } else if (range.length() == 3 && range.at(1) == '-') {
+ QChar from = range.at(0);
+ QChar to = range.at(2);
+ for (QChar ix = from; ix <= to; ix = QChar(ix.unicode() + 1)){
+ lines += QString(ix)+ "\n";
+ }
+ } else {
+ say(LOG_ERROR, QObject::tr("wrong range: use <from>-<to> or <from>-<to>,<step>"));
+ }
+ if (! lines.isEmpty()){
+ QString content = ui->plainTextEditValues->toPlainText();
+ if (! content.isEmpty() && ! content.endsWith("\n"))
+ lines = "\n" + lines;
+ ui->plainTextEditValues->setPlainText(content + lines);
+ }
+}
+
/**
* Executes the current commands.
*/
void MainWindow::onRun()
{
- QString text = ui->textEditPad->toPlainText();
+ QString text = ui->plainTextEditPad->toPlainText();
int length = text.length();
- int position = min(ui->textEditPad->textCursor().position(), length - 1);
+ int position = min(ui->plainTextEditPad->textCursor().position(), length - 1);
int pos1;
for (pos1 = position; pos1 > 0; pos1--){
if (text.at(pos1) == '\n' && text.at(pos1 - 1) == '\n')
}
if (pos2 < length - 1 && text.at(pos2 + 1) != '\n')
pos2++;
- ui->textEditResult->clear();
+ ui->plainTextEditResult->clear();
QString script = text.mid(pos1, pos2 - pos1 + 1);
if (script.length() > 10 || script.trimmed().length() > 0)
m_processor->interpret(script);
QString fname = m_homeDir + "pad.txt";
QByteArray content;
ReFileUtils::readFromFile(I18N::s2b(fname).constData(), content);
- ui->textEditPad->setText(QString::fromUtf8(content));
+ ui->plainTextEditPad->setPlainText(QString::fromUtf8(content));
}
{
QString fname = m_homeDir + "pad.txt";
ReFileUtils::writeToFile(I18N::s2b(fname).constData(),
- ui->textEditPad->toPlainText().toUtf8().constData());
+ ui->plainTextEditPad->toPlainText().toUtf8().constData());
}
/**
msg = "+ ";
break;
case LOG_ERROR:
+ setStatusMessage(level, message);
msg = "! ";
break;
default:
ui->listWidgetResult->addItem(msg + message);
ui->listWidgetResult->setCurrentRow(ui->listWidgetResult->count() - 1);
- QString edit = ui->textEditResult->toPlainText();
+ QString edit = ui->plainTextEditResult->toPlainText();
if (! edit.isEmpty() && ! edit.endsWith("\n")){
msg += "\n";
}
msg += message;
edit += msg;
- ui->textEditResult->setPlainText(edit);
+ ui->plainTextEditResult->setPlainText(edit);
return level >= LOG_INFO;
}
virtual void onGuiTimerUpdate();
void onClearEdit();
void onClearList();
+ void onExpand();
+ void onInterpolate();
void onLoad();
void onRun();
void onSave();
</layout>
</item>
<item>
- <widget class="QTextEdit" name="textEditPad"/>
+ <widget class="QPlainTextEdit" name="plainTextEditPad"/>
</item>
</layout>
</widget>
<widget class="QTabWidget" name="tabWidgetResult">
<property name="currentIndex">
- <number>0</number>
+ <number>2</number>
</property>
<widget class="QWidget" name="tabList">
<attribute name="title">
</layout>
</item>
<item>
- <widget class="QTextEdit" name="textEditResult">
+ <widget class="QPlainTextEdit" name="plainTextEditResult">
<property name="font">
<font>
<family>FreeMono</family>
</item>
</layout>
</widget>
+ <widget class="QWidget" name="tabBuffers">
+ <attribute name="title">
+ <string>Buffers</string>
+ </attribute>
+ <layout class="QVBoxLayout" name="verticalLayout_8">
+ <item>
+ <widget class="QSplitter" name="splitter_2">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <widget class="QWidget" name="layoutWidget">
+ <layout class="QVBoxLayout" name="verticalLayout_7">
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout_5">
+ <item>
+ <widget class="QLabel" name="label_2">
+ <property name="text">
+ <string>B0! (input)</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <spacer name="horizontalSpacer_5">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <widget class="QLabel" name="label_4">
+ <property name="text">
+ <string>Var:</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QLineEdit" name="lineEditVariable">
+ <property name="maximumSize">
+ <size>
+ <width>75</width>
+ <height>16777215</height>
+ </size>
+ </property>
+ <property name="text">
+ <string>$$$</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QPushButton" name="pushButtonExpand">
+ <property name="toolTip">
+ <string>Copies the input buffer multiple times and replaces the variable with the values. Each line of B1! defines gives one block in the result buffer</string>
+ </property>
+ <property name="text">
+ <string>Expand</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <widget class="QPlainTextEdit" name="plainTextEditInput"/>
+ </item>
+ </layout>
+ </widget>
+ <widget class="QWidget" name="layoutWidget">
+ <layout class="QVBoxLayout" name="verticalLayout_6">
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout_2">
+ <item>
+ <widget class="QLabel" name="label_3">
+ <property name="text">
+ <string>B1! (values)</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <spacer name="horizontalSpacer_4">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <widget class="QLabel" name="label_5">
+ <property name="text">
+ <string>Range:</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QLineEdit" name="lineEditRange">
+ <property name="maximumSize">
+ <size>
+ <width>125</width>
+ <height>16777215</height>
+ </size>
+ </property>
+ <property name="toolTip">
+ <string>Rage to create values, e.g. "2-64,3", "A-F"</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QPushButton" name="pushButtonInterpolate">
+ <property name="toolTip">
+ <string>Converts the range into values (appended at the end)</string>
+ </property>
+ <property name="text">
+ <string>Interpol.</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <widget class="QPlainTextEdit" name="plainTextEditValues"/>
+ </item>
+ </layout>
+ </widget>
+ </widget>
+ </item>
+ </layout>
+ </widget>
</widget>
</widget>
</item>
}
/**
- * Returns a readable string for a duration given by <code>clock_t</code>.
+ * Returns a readable string for a duration given by milliseconds.
*
* @param durationMilliSec a duration in msec
*
}
return rc;
}
-
+/**
+ * Returns a readable string for a duration given by <code>clock_t</code>.
+ *
+ * @param start the time of the start
+ * @param factor the factor of the estimated runtime, should be < 1.0
+ *
+ * @return a string describing the current runtime and the estimation.
+ */
+QString ReQStringUtils::runtimeEstimation(const QDateTime& start,
+ double factor){
+ qint64 duration = QDateTime::currentMSecsSinceEpoch() - start.currentMSecsSinceEpoch();
+ if (factor < 1)
+ factor = 1;
+ else if (factor <= 0.001)
+ factor = 0.001;
+ qint64 estimated = qint64((double) duration / factor);
+ QString rc = QObject::tr("%1 of %2").arg(readableDuration(duration))
+ .arg(readableDuration(estimated));
+ return rc;
+}
/**
* Returns a readable string for a filesize.
*
static QString readableSize(int64_t filesize);
static bool replacePlaceholders(QString& text,
const QMap<QString, QString>& placeholders, QString* error);
+ static QString runtimeEstimation(const QDateTime& start, double factor);
static void skipExpected(const ReString& text, QChar expected, int& index,
int& length);
/**