File indexing completed on 2025-02-16 10:53:50

0001 /* This file is part of the KDE project
0002    SPDX-FileCopyrightText: 1999 David Faure <faure@kde.org>
0003    SPDX-FileCopyrightText: 2004 Nicolas GOUTTE <goutte@kde.org>
0004 
0005    SPDX-License-Identifier: LGPL-2.0-or-later
0006 */
0007 
0008 #include "csvexportdialog.h"
0009 #include "csvexport.h"
0010 
0011 #include "sheets/engine/SheetBase.h"
0012 #include "sheets/core/Map.h"
0013 
0014 #include <kcharsets.h>
0015 #include <kmessagebox.h>
0016 #include <KSharedConfig>
0017 
0018 #include <QButtonGroup>
0019 #include <QGroupBox>
0020 #include <QGuiApplication>
0021 #include <QTextCodec>
0022 
0023 using namespace Calligra::Sheets;
0024 
0025 CSVExportDialog::CSVExportDialog(QWidget * parent)
0026         : KoDialog(parent),
0027         m_dialog(new ExportDialogUI(this)),
0028         m_delimiter(","),
0029         m_textquote('"')
0030 {
0031     setButtons(KoDialog::Ok | KoDialog::Cancel);
0032     setDefaultButton(KoDialog::Ok);
0033     QGuiApplication::restoreOverrideCursor();
0034 
0035     QStringList encodings;
0036     encodings << i18nc("Descriptive encoding name", "Recommended ( %1 )" , "UTF-8");
0037     encodings << i18nc("Descriptive encoding name", "Locale ( %1 )" , QString(QTextCodec::codecForLocale()->name()));
0038     encodings += KCharsets::charsets()->descriptiveEncodingNames();
0039     // Add a few non-standard encodings, which might be useful for text files
0040     const QString description(i18nc("Descriptive encoding name", "Other ( %1 )"));
0041     encodings << description.arg("Apple Roman"); // Apple
0042     encodings << description.arg("IBM 850") << description.arg("IBM 866"); // MS DOS
0043     encodings << description.arg("CP 1258"); // Windows
0044 
0045     m_dialog->comboBoxEncoding->addItems(encodings);
0046 
0047     setMainWidget(m_dialog);
0048 
0049     QButtonGroup *group = new QButtonGroup(m_dialog);
0050     group->addButton(m_dialog->m_radioComma, 0);
0051     group->addButton(m_dialog->m_radioSemicolon, 1);
0052     group->addButton(m_dialog->m_radioTab, 2);
0053     group->addButton(m_dialog->m_radioSpace, 3);
0054     group->addButton(m_dialog->m_radioOther, 4);
0055 
0056     // Invalid 'Other' delimiters
0057     // - Quotes
0058     // - CR,LF,Vertical-tab,Formfeed,ASCII bel
0059     QRegExp rx("^[^\"'\r\n\v\f\a]{0,1}$");
0060     m_delimiterValidator = new QRegExpValidator(rx, m_dialog->m_delimiterBox);
0061     m_dialog->m_delimiterEdit->setValidator(m_delimiterValidator);
0062 
0063     connect(group, &QButtonGroup::idClicked,
0064             this, &CSVExportDialog::delimiterClicked);
0065     connect(m_dialog->m_delimiterEdit, &QLineEdit::returnPressed,
0066             this, &CSVExportDialog::returnPressed);
0067     connect(m_dialog->m_delimiterEdit, &QLineEdit::textChanged,
0068             this, &CSVExportDialog::textChanged);
0069     connect(m_dialog->m_comboQuote, QOverload<const QString &>::of(&QComboBox::activated),
0070             this, &CSVExportDialog::textquoteSelected);
0071     connect(m_dialog->m_selectionOnly, &QAbstractButton::toggled,
0072             this, &CSVExportDialog::selectionOnlyChanged);
0073     connect(this, &KoDialog::okClicked, this, &CSVExportDialog::slotOk);
0074     connect(this, &KoDialog::cancelClicked, this, &CSVExportDialog::slotCancel);
0075 
0076     loadSettings();
0077 }
0078 
0079 CSVExportDialog::~CSVExportDialog()
0080 {
0081     saveSettings();
0082     QGuiApplication::setOverrideCursor(Qt::WaitCursor);
0083     delete m_delimiterValidator;
0084 }
0085 
0086 void CSVExportDialog::loadSettings()
0087 {
0088     KConfigGroup configGroup = KSharedConfig::openConfig()->group("CSVDialog Settings");
0089     m_textquote = configGroup.readEntry("textQuote", "\"")[0];
0090     m_delimiter = configGroup.readEntry("delimiter", ",");
0091     const QString codecText = configGroup.readEntry("codec", "");
0092     bool selectionOnly = configGroup.readEntry("selectionOnly", false);
0093     const QString sheetDelim = configGroup.readEntry("sheetDelimiter", m_dialog->m_sheetDelimiter->text());
0094     bool delimAbove = configGroup.readEntry("sheetDelimiterAbove", false);
0095     const QString eol = configGroup.readEntry("eol", "\r\n");
0096 
0097     // update widgets
0098     if (!codecText.isEmpty()) {
0099         m_dialog->comboBoxEncoding->setCurrentIndex(m_dialog->comboBoxEncoding->findText(codecText));
0100     }
0101     if (m_delimiter == ",")
0102         m_dialog->m_radioComma->setChecked(true);
0103     else if (m_delimiter == "\t")
0104         m_dialog->m_radioTab->setChecked(true);
0105     else if (m_delimiter == " ")
0106         m_dialog->m_radioSpace->setChecked(true);
0107     else if (m_delimiter == ";")
0108         m_dialog->m_radioSemicolon->setChecked(true);
0109     else {
0110         m_dialog->m_radioOther->setChecked(true);
0111         m_dialog->m_delimiterEdit->setText(m_delimiter);
0112     }
0113     m_dialog->m_comboQuote->setCurrentIndex(m_textquote == '\'' ? 1 : m_textquote == '"' ? 0 : 2);
0114     m_dialog->m_selectionOnly->setChecked(selectionOnly);
0115     m_dialog->m_sheetDelimiter->setText(sheetDelim);
0116     m_dialog->m_delimiterAboveAll->setChecked(delimAbove);
0117     if (eol == "\r\n")
0118         m_dialog->radioEndOfLineCRLF->setChecked(true);
0119     else if (eol == "\r")
0120         m_dialog->radioEndOfLineCR->setChecked(true);
0121     else
0122         m_dialog->radioEndOfLineLF->setChecked(true);
0123 }
0124 
0125 void CSVExportDialog::saveSettings()
0126 {
0127     KConfigGroup configGroup = KSharedConfig::openConfig()->group("CSVDialog Settings");
0128     configGroup.writeEntry("textQuote", QString(m_textquote));
0129     configGroup.writeEntry("delimiter", m_delimiter);
0130     configGroup.writeEntry("codec", m_dialog->comboBoxEncoding->currentText());
0131     configGroup.writeEntry("selectionOnly", exportSelectionOnly());
0132     configGroup.writeEntry("sheetDelimiter", getSheetDelimiter());
0133     configGroup.writeEntry("sheetDelimiterAbove", printAlwaysSheetDelimiter());
0134     configGroup.writeEntry("eol", getEndOfLine());
0135     configGroup.sync();
0136 }
0137 
0138 void CSVExportDialog::fillSheet(Map * map)
0139 {
0140     m_dialog->m_sheetList->clear();
0141     QListWidgetItem *item;
0142 
0143     for(SheetBase* sheet : map->sheetList()) {
0144         item = new QListWidgetItem(sheet->sheetName(), m_dialog->m_sheetList);
0145         item->setCheckState(Qt::Checked);
0146         m_dialog->m_sheetList->addItem(item);
0147     }
0148 }
0149 
0150 QChar CSVExportDialog::getDelimiter() const
0151 {
0152     return m_delimiter[0];
0153 }
0154 
0155 QChar CSVExportDialog::getTextQuote() const
0156 {
0157     return m_textquote;
0158 }
0159 
0160 bool CSVExportDialog::printAlwaysSheetDelimiter() const
0161 {
0162     return m_dialog->m_delimiterAboveAll->isChecked();
0163 }
0164 
0165 QString CSVExportDialog::getSheetDelimiter() const
0166 {
0167     return m_dialog->m_sheetDelimiter->text();
0168 }
0169 
0170 bool CSVExportDialog::exportSheet(QString const & sheetName) const
0171 {
0172     for (int i = 0; i < m_dialog->m_sheetList->count(); ++i) {
0173         QListWidgetItem *const item = m_dialog->m_sheetList->item(i);
0174         if (item->checkState() == Qt::Checked) {
0175             if (item->text() == sheetName) {
0176                 return true;
0177             }
0178         }
0179     }
0180     return false;
0181 }
0182 
0183 void CSVExportDialog::slotOk()
0184 {
0185     accept();
0186 }
0187 
0188 void CSVExportDialog::slotCancel()
0189 {
0190     reject();
0191 }
0192 
0193 void CSVExportDialog::returnPressed()
0194 {
0195     if (!m_dialog->m_radioOther->isChecked())
0196         return;
0197 
0198     m_delimiter = m_dialog->m_delimiterEdit->text();
0199 }
0200 
0201 void CSVExportDialog::textChanged(const QString &)
0202 {
0203 
0204     if (m_dialog->m_delimiterEdit->text().isEmpty()) {
0205         enableButtonOk(! m_dialog->m_radioOther->isChecked());
0206         return;
0207     }
0208 
0209     m_dialog->m_radioOther->setChecked(true);
0210     delimiterClicked(4);
0211 }
0212 
0213 void CSVExportDialog::delimiterClicked(int id)
0214 {
0215     enableButtonOk(true);
0216 
0217     //Erase "Other Delimiter" text box if the user has selected one of
0218     //the standard options instead (comma, semicolon, tab or space)
0219     if (id != 4)
0220         m_dialog->m_delimiterEdit->setText("");
0221 
0222     switch (id) {
0223     case 0: // comma
0224         m_delimiter = ",";
0225         break;
0226     case 1: // semicolon
0227         m_delimiter = ";";
0228         break;
0229     case 2: // tab
0230         m_delimiter = "\t";
0231         break;
0232     case 3: // space
0233         m_delimiter = " ";
0234         break;
0235     case 4: // other
0236         enableButtonOk(! m_dialog->m_delimiterEdit->text().isEmpty());
0237         m_delimiter = m_dialog->m_delimiterEdit->text();
0238         break;
0239     }
0240 }
0241 
0242 void CSVExportDialog::textquoteSelected(const QString & mark)
0243 {
0244     m_textquote = mark[0];
0245 }
0246 
0247 void CSVExportDialog::selectionOnlyChanged(bool on)
0248 {
0249     m_dialog->m_sheetList->setEnabled(!on);
0250     m_dialog->m_delimiterLineBox->setEnabled(!on);
0251 
0252     if (on)
0253         m_dialog->m_tabWidget->setCurrentIndex(1);
0254 }
0255 
0256 bool CSVExportDialog::exportSelectionOnly() const
0257 {
0258     return m_dialog->m_selectionOnly->isChecked();
0259 }
0260 
0261 QTextCodec* CSVExportDialog::getCodec(void) const
0262 {
0263     const QString strCodec(KCharsets::charsets()->encodingForName(m_dialog->comboBoxEncoding->currentText()));
0264     qDebug(lcCsvExport) << "Encoding:" << strCodec;
0265 
0266     bool ok = false;
0267     QTextCodec* codec = QTextCodec::codecForName(strCodec.toUtf8());
0268 
0269     // If QTextCodec has not found a valid encoding, so try with KCharsets.
0270     if (codec) {
0271         ok = true;
0272     } else {
0273         codec = KCharsets::charsets()->codecForName(strCodec, ok);
0274     }
0275 
0276     // Still nothing?
0277     if (!codec || !ok) {
0278         // Default: UTF-8
0279         qWarning(lcCsvExport) << "Cannot find encoding:" << strCodec;
0280         // ### TODO: what parent to use?
0281         KMessageBox::error(0, i18n("Cannot find encoding: %1", strCodec));
0282         return 0;
0283     }
0284 
0285     return codec;
0286 }
0287 
0288 QString CSVExportDialog::getEndOfLine(void) const
0289 {
0290     QString strReturn;
0291     if (m_dialog->radioEndOfLineLF->isChecked())
0292         strReturn = "\n";
0293     else if (m_dialog->radioEndOfLineCRLF->isChecked())
0294         strReturn = "\r\n";
0295     else if (m_dialog->radioEndOfLineCR->isChecked())
0296         strReturn = "\r";
0297     else
0298         strReturn = "\n";
0299 
0300     return strReturn;
0301 }