Changeset - e798d26ab38b
[Not reviewed]
default
0 3 0
Hasan Yavuz Ă–ZDERYA - 7 years ago 2018-07-07 12:54:52
hy@ozderya.net
entering record file name by text input and timestamp options
3 files changed with 120 insertions and 39 deletions:
0 comments (0 inline, 0 general)
src/recordpanel.cpp
Show inline comments
 
@@ -14,25 +14,29 @@
 
  GNU General Public License for more details.
 

	
 
  You should have received a copy of the GNU General Public License
 
  along with serialplot.  If not, see <http://www.gnu.org/licenses/>.
 
*/
 

	
 
#include <QIcon>
 
#include <QFile>
 
#include <QFileInfo>
 
#include <QMessageBox>
 
#include <QFileDialog>
 
#include <QRegularExpression>
 
#include <QCompleter>
 
#include <QFileSystemModel>
 
#include <QDirModel>
 
#include <QtDebug>
 
#include <ctime>
 

	
 
#include "recordpanel.h"
 
#include "ui_recordpanel.h"
 
#include "setting_defines.h"
 

	
 
RecordPanel::RecordPanel(Stream* stream, QWidget *parent) :
 
    QWidget(parent),
 
    ui(new Ui::RecordPanel),
 
    recordToolBar(tr("Record Toolbar")),
 
    recordAction(QIcon::fromTheme("media-record"), tr("Record"), this),
 
    recorder(this)
 
{
 
@@ -62,24 +66,30 @@ RecordPanel::RecordPanel(Stream* stream,
 
            });
 

	
 
    connect(ui->cbWindowsLE, &QCheckBox::toggled,
 
            [this](bool enabled)
 
            {
 
                recorder.windowsLE = enabled;
 
            });
 

	
 
    connect(&recordAction, &QAction::toggled, ui->cbWindowsLE, &QWidget::setDisabled);
 
    connect(&recordAction, &QAction::toggled, ui->cbTimestamp, &QWidget::setDisabled);
 
    connect(&recordAction, &QAction::toggled, ui->leSeparator, &QWidget::setDisabled);
 
    connect(&recordAction, &QAction::toggled, ui->pbBrowse, &QWidget::setDisabled);
 

	
 
    QCompleter *completer = new QCompleter(this);
 
    // TODO: QDirModel is deprecated, use QFileSystemModel (but it doesn't work)
 
    completer->setModel(new QDirModel(completer));
 
    completer->setCaseSensitivity(Qt::CaseInsensitive);
 
    ui->leFileName->setCompleter(completer);
 
}
 

	
 
RecordPanel::~RecordPanel()
 
{
 
    delete ui;
 
}
 

	
 
QToolBar* RecordPanel::toolbar()
 
{
 
    return &recordToolBar;
 
}
 

	
 
@@ -90,81 +100,132 @@ bool RecordPanel::recordPaused()
 

	
 
bool RecordPanel::selectFile()
 
{
 
    QString fileName = QFileDialog::getSaveFileName(
 
        parentWidget(), tr("Select recording file"));
 

	
 
    if (fileName.isEmpty())
 
    {
 
        return false;
 
    }
 
    else
 
    {
 
        selectedFile = fileName;
 
        ui->lbFileName->setText(selectedFile);
 
        setSelectedFile(fileName);
 
        overwriteSelected = QFile::exists(fileName);
 
        return true;
 
    }
 
}
 

	
 
QString RecordPanel::selectedFile() const
 
{
 
    return ui->leFileName->text();
 
}
 

	
 
void RecordPanel::setSelectedFile(QString f)
 
{
 
    ui->leFileName->setText(f);
 
}
 

	
 
QString RecordPanel::getSelectedFile()
 
{
 
    if (selectedFile().isEmpty())
 
    {
 
        if (!selectFile()) return QString();
 
    }
 

	
 
    // assume that file name contains a time format specifier
 
    if (selectedFile().contains("%"))
 
    {
 
        auto ts = formatTimeStamp(selectedFile());
 
        if (!QFile::exists(ts) || // file doesn't exists
 
            confirmOverwrite(ts)) // exists but user accepted overwrite
 
        {
 
            return ts;
 
        }
 
        return QString();
 
    }
 

	
 
    // if no timestamp and file exists try autoincrement option
 
    if (!overwriteSelected && QFile::exists(selectedFile()))
 
    {
 
        if (ui->cbAutoIncrement->isChecked())
 
        {
 
            if (!incrementFileName()) return QString();
 
        }
 
        else
 
        {
 
            if (!confirmOverwrite(selectedFile()))
 
                return QString();
 
        }
 
    }
 

	
 
    return selectedFile();
 
}
 

	
 
QString RecordPanel::formatTimeStamp(QString t) const
 
{
 
    auto maxSize = t.size() + 1024;
 
    auto r = new char[maxSize];
 

	
 
    time_t rawtime;
 
    struct tm * timeinfo;
 

	
 
    time(&rawtime);
 
    timeinfo = localtime (&rawtime);
 
    strftime(r, maxSize, t.toLatin1().data(), timeinfo);
 

	
 
    auto rs = QString(r);
 
    delete r;
 
    return rs;
 
}
 

	
 
void RecordPanel::onRecord(bool start)
 
{
 
    if (!start)
 
    {
 
        stopRecording();
 
        return;
 
    }
 

	
 
    bool canceled = false;
 
    if (ui->leSeparator->text().isEmpty())
 
    {
 
        QMessageBox::critical(this, "Error",
 
                              "Column separator cannot be empty! Please select a separator.");
 
        ui->leSeparator->setFocus(Qt::OtherFocusReason);
 
        canceled = true;
 
    }
 

	
 
    // check file name
 
    if (!canceled && selectedFile.isEmpty() && !selectFile())
 
    {
 
        canceled = true;
 
    }
 

	
 
    if (!canceled && !overwriteSelected && QFile::exists(selectedFile))
 
    QString fn;
 
    if (!canceled)
 
    {
 
        if (ui->cbAutoIncrement->isChecked())
 
        {
 
            // TODO: should we increment even if user selected to replace?
 
            canceled = !incrementFileName();
 
        }
 
        else
 
        {
 
            canceled = !confirmOverwrite(selectedFile);
 
        }
 
        fn = getSelectedFile();
 
        canceled = fn.isEmpty();
 
    }
 

	
 
    if (canceled)
 
    {
 
        recordAction.setChecked(false);
 
    }
 
    else
 
    {
 
        overwriteSelected = false;
 
        startRecording();
 
        startRecording(fn);
 
    }
 
}
 

	
 
bool RecordPanel::incrementFileName(void)
 
{
 
    QFileInfo fileInfo(selectedFile);
 
    QFileInfo fileInfo(selectedFile());
 

	
 
    QString base = fileInfo.completeBaseName();
 
    QRegularExpression regex("(.*?)(\\d+)(?!.*\\d)(.*)");
 
    auto match = regex.match(base);
 

	
 
    if (match.hasMatch())
 
    {
 
        bool ok;
 
        int fileNum = match.captured(2).toInt(&ok);
 
        base = match.captured(1) + QString::number(fileNum + 1) + match.captured(3);
 
    }
 
    else
 
@@ -181,28 +242,27 @@ bool RecordPanel::incrementFileName(void
 
    QString autoFileName = fileInfo.path() + "/" + base + suffix;
 

	
 
    // check if auto generated file name exists, ask user another name
 
    if (QFile::exists(autoFileName))
 
    {
 
        if (!confirmOverwrite(autoFileName))
 
        {
 
            return false;
 
        }
 
    }
 
    else
 
    {
 
        selectedFile = autoFileName;
 
        setSelectedFile(autoFileName);
 
    }
 

	
 
    ui->lbFileName->setText(selectedFile);
 
    return true;
 
}
 

	
 
bool RecordPanel::confirmOverwrite(QString fileName)
 
{
 
    // prepare message box
 
    QMessageBox mb(parentWidget());
 
    mb.setWindowTitle(tr("File Already Exists"));
 
    mb.setIcon(QMessageBox::Warning);
 
    mb.setText(tr("File (%1) already exists. How to continue?").arg(fileName));
 

	
 
    auto bCancel    = mb.addButton(QMessageBox::Cancel);
 
@@ -211,41 +271,41 @@ bool RecordPanel::confirmOverwrite(QStri
 

	
 
    mb.setEscapeButton(bCancel);
 

	
 
    // show message box
 
    mb.exec();
 

	
 
    if (mb.clickedButton() == bCancel)
 
    {
 
        return false;
 
    }
 
    else if (mb.clickedButton() == bOverwrite)
 
    {
 
        selectedFile = fileName;
 
        setSelectedFile(fileName);
 
        return true;
 
    }
 
    else                    // select button
 
    {
 
        return selectFile();
 
    }
 
}
 

	
 
void RecordPanel::startRecording(void)
 
void RecordPanel::startRecording(QString fileName)
 
{
 
    QStringList channelNames;
 
    if (ui->cbHeader->isChecked())
 
    {
 
        channelNames = _stream->infoModel()->channelNames();
 
    }
 
    if (recorder.startRecording(selectedFile, getSeparator(),
 
    if (recorder.startRecording(fileName, getSeparator(),
 
                                channelNames, ui->cbTimestamp->isChecked()))
 
    {
 
        _stream->connectFollower(&recorder);
 
    }
 
}
 

	
 
void RecordPanel::stopRecording(void)
 
{
 
    recorder.stopRecording();
 
    _stream->disconnectFollower(&recorder);
 
}
 

	
src/recordpanel.h
Show inline comments
 
@@ -53,25 +53,24 @@ signals:
 
    void recordStarted();
 
    void recordStopped();
 
    void recordPausedChanged(bool enabled);
 

	
 
public slots:
 
    /// Must be called when port is closed
 
    void onPortClose();
 

	
 
private:
 
    Ui::RecordPanel *ui;
 
    QToolBar recordToolBar;
 
    QAction recordAction;
 
    QString selectedFile;
 
    bool overwriteSelected;
 
    DataRecorder recorder;
 
    Stream* _stream;
 

	
 
    /**
 
     * @brief Increments the file name.
 
     *
 
     * If file name doesn't have a number at the end of it, a number is appended
 
     * with underscore starting from 1.
 
     *
 
     * @return false if user cancels
 
     */
 
@@ -81,25 +80,44 @@ private:
 
     * @brief Used to ask user confirmation if auto generated file
 
     * name exists.
 
     *
 
     * If user confirms overwrite, `selectedFile` is set to
 
     * `fileName`. User is also given option to select file and is
 
     * shown a file select dialog in this case.
 
     *
 
     * @param fileName auto generated file name.
 
     * @return false if user cancels
 
     */
 
    bool confirmOverwrite(QString fileName);
 

	
 
    void startRecording(void);
 
    /// Returns filename in edit box. May be invalid!
 
    QString selectedFile() const;
 
    /// Sets the filename in edit box.
 
    void setSelectedFile(QString f);
 

	
 
    /**
 
     * Tries to get a valid file name by handling user interactions and
 
     * automatic naming (increment, timestamp etc).
 
     *
 
     * Returned file name can be used immediately. File name box should also be
 
     * set to selected file name.
 
     *
 
     * @return empty if failure otherwise valid filename
 
     */
 
    QString getSelectedFile();
 

	
 
    /// Formats timestamp in given text
 
    QString formatTimeStamp(QString t) const;
 

	
 
    void startRecording(QString fileName);
 
    void stopRecording(void);
 

	
 
    /// Returns separator text from ui. "\t" is converted to TAB
 
    /// character.
 
    QString getSeparator() const;
 

	
 
private slots:
 
    /**
 
     * @brief Opens up the file select dialog
 
     *
 
     * If you cancel the selection operation, currently selected file is not
 
     * changed.
src/recordpanel.ui
Show inline comments
 
@@ -10,46 +10,49 @@
 
    <height>207</height>
 
   </rect>
 
  </property>
 
  <property name="windowTitle">
 
   <string>Form</string>
 
  </property>
 
  <layout class="QHBoxLayout" name="horizontalLayout_2">
 
   <item>
 
    <layout class="QVBoxLayout" name="verticalLayout">
 
     <item>
 
      <layout class="QHBoxLayout" name="horizontalLayout">
 
       <item>
 
        <widget class="QLineEdit" name="leFileName">
 
         <property name="sizePolicy">
 
          <sizepolicy hsizetype="MinimumExpanding" vsizetype="Fixed">
 
           <horstretch>0</horstretch>
 
           <verstretch>0</verstretch>
 
          </sizepolicy>
 
         </property>
 
         <property name="toolTip">
 
          <string>You can use C `strftime` function format specifiers for timestamps in your file name.</string>
 
         </property>
 
         <property name="placeholderText">
 
          <string>Enter file name or browse</string>
 
         </property>
 
        </widget>
 
       </item>
 
       <item>
 
        <widget class="QPushButton" name="pbBrowse">
 
         <property name="toolTip">
 
          <string>Select record file</string>
 
         </property>
 
         <property name="text">
 
          <string>Browse</string>
 
         </property>
 
        </widget>
 
       </item>
 
       <item>
 
        <widget class="QLabel" name="lbFileName">
 
         <property name="sizePolicy">
 
          <sizepolicy hsizetype="MinimumExpanding" vsizetype="Preferred">
 
           <horstretch>0</horstretch>
 
           <verstretch>0</verstretch>
 
          </sizepolicy>
 
         </property>
 
         <property name="text">
 
          <string>Select file...</string>
 
         </property>
 
        </widget>
 
       </item>
 
      </layout>
 
     </item>
 
     <item>
 
      <layout class="QGridLayout" name="gridLayout">
 
       <item row="2" column="1">
 
        <widget class="QCheckBox" name="cbStopOnClose">
 
         <property name="text">
 
          <string>Stop recording when port closed</string>
 
         </property>
 
         <property name="checked">
 
          <bool>true</bool>
 
         </property>
0 comments (0 inline, 0 general)