File indexing completed on 2025-01-19 04:46:31
0001 /* 0002 SPDX-FileCopyrightText: 2016-2024 Laurent Montel <montel@kde.org> 0003 0004 SPDX-License-Identifier: GPL-2.0-or-later 0005 */ 0006 0007 #include "csvimportexportplugininterface.h" 0008 #include "import/csvimportdialog.h" 0009 #include <KActionCollection> 0010 #include <KIO/Job> 0011 #include <KJobWidgets> 0012 #include <KLocalizedString> 0013 #include <KMessageBox> 0014 #include <PimCommon/RenameFileDialog> 0015 #include <QAction> 0016 #include <QFileDialog> 0017 #include <QFileInfo> 0018 #include <QPointer> 0019 #include <QTemporaryFile> 0020 #include <QTextCodec> 0021 #include <QTextStream> 0022 0023 #include <KAddressBookImportExport/ContactSelectionDialog> 0024 #include <KAddressBookImportExport/ImportExportEngine> 0025 0026 CSVImportExportPluginInterface::CSVImportExportPluginInterface(QObject *parent) 0027 : KAddressBookImportExport::PluginInterface(parent) 0028 { 0029 } 0030 0031 CSVImportExportPluginInterface::~CSVImportExportPluginInterface() = default; 0032 0033 void CSVImportExportPluginInterface::createAction(KActionCollection *ac) 0034 { 0035 QAction *action = ac->addAction(QStringLiteral("file_export_csv")); 0036 action->setText(i18n("Export CSV file...")); 0037 action->setWhatsThis(i18n("Export contacts to a file in comma separated value format.")); 0038 setExportActions(QList<QAction *>() << action); 0039 connect(action, &QAction::triggered, this, &CSVImportExportPluginInterface::slotExportCVS); 0040 0041 action = ac->addAction(QStringLiteral("file_import_csv")); 0042 action->setText(i18n("Import CSV file...")); 0043 action->setWhatsThis(i18n("Import contacts from a file in comma separated value format.")); 0044 setImportActions(QList<QAction *>() << action); 0045 connect(action, &QAction::triggered, this, &CSVImportExportPluginInterface::slotImportCVS); 0046 } 0047 0048 void CSVImportExportPluginInterface::exec() 0049 { 0050 switch (mImportExportAction) { 0051 case Import: 0052 importCSV(); 0053 break; 0054 case Export: 0055 exportCSV(); 0056 break; 0057 } 0058 } 0059 0060 void CSVImportExportPluginInterface::importCSV() 0061 { 0062 KAddressBookImportExport::ContactList contactList; 0063 QPointer<CSVImportDialog> dlg = new CSVImportDialog(parentWidget()); 0064 if (dlg->exec()) { 0065 contactList.setAddressList(dlg->contacts()); 0066 } 0067 0068 delete dlg; 0069 auto engine = new KAddressBookImportExport::ImportExportEngine(this); 0070 engine->setContactList(contactList); 0071 engine->setDefaultAddressBook(defaultCollection()); 0072 engine->importContacts(); 0073 } 0074 0075 void CSVImportExportPluginInterface::slotImportCVS() 0076 { 0077 mImportExportAction = Import; 0078 Q_EMIT emitPluginActivated(this); 0079 } 0080 0081 void CSVImportExportPluginInterface::slotExportCVS() 0082 { 0083 mImportExportAction = Export; 0084 Q_EMIT emitPluginActivated(this); 0085 } 0086 0087 void CSVImportExportPluginInterface::exportToFile(QFile *file, const KContacts::Addressee::List &contacts) const 0088 { 0089 QTextStream stream(file); 0090 stream.setEncoding(QStringConverter::System); 0091 0092 auto fields = KAddressBookImportExport::ContactFields::allFields(); 0093 fields.remove(KAddressBookImportExport::ContactFields::Undefined); 0094 0095 bool first = true; 0096 0097 // First output the column headings 0098 const int fieldsCount(fields.count()); 0099 for (int i = 0; i < fieldsCount; ++i) { 0100 if (!first) { 0101 stream << ","; 0102 } 0103 0104 // add quoting as defined in RFC 4180 0105 QString label = KAddressBookImportExport::ContactFields::label(fields.at(i)); 0106 label.replace(QLatin1Char('"'), QStringLiteral("\"\"")); 0107 0108 stream << "\"" << label << "\""; 0109 first = false; 0110 } 0111 stream << "\n"; 0112 0113 // Then all the contacts 0114 for (int i = 0; i < contacts.count(); ++i) { 0115 const KContacts::Addressee contact = contacts.at(i); 0116 first = true; 0117 0118 for (int j = 0; j < fields.count(); ++j) { 0119 if (!first) { 0120 stream << ","; 0121 } 0122 0123 QString content; 0124 if (fields.at(j) == KAddressBookImportExport::ContactFields::Birthday || fields.at(j) == KAddressBookImportExport::ContactFields::Anniversary) { 0125 const QDateTime dateTime = QDateTime::fromString(KAddressBookImportExport::ContactFields::value(fields.at(j), contact), Qt::ISODate); 0126 if (dateTime.isValid()) { 0127 content = dateTime.date().toString(Qt::ISODate); 0128 } 0129 } else { 0130 content = KAddressBookImportExport::ContactFields::value(fields.at(j), contact).replace(QLatin1Char('\n'), QStringLiteral("\\n")); 0131 } 0132 0133 // add quoting as defined in RFC 4180 0134 content.replace(QLatin1Char('"'), QStringLiteral("\"\"")); 0135 0136 stream << '\"' << content << '\"'; 0137 first = false; 0138 } 0139 0140 stream << "\n"; 0141 } 0142 } 0143 0144 void CSVImportExportPluginInterface::exportCSV() 0145 { 0146 QPointer<KAddressBookImportExport::ContactSelectionDialog> dlg = 0147 new KAddressBookImportExport::ContactSelectionDialog(itemSelectionModel(), false, parentWidget()); 0148 dlg->setMessageText(i18n("Which contact do you want to export?")); 0149 dlg->setDefaultAddressBook(defaultCollection()); 0150 if (!dlg->exec()) { 0151 delete dlg; 0152 return; 0153 } 0154 const KContacts::AddresseeList contacts = dlg->selectedContacts().addressList(); 0155 delete dlg; 0156 0157 if (contacts.isEmpty()) { 0158 KMessageBox::error(nullptr, i18n("You have not selected any contacts to export.")); 0159 return; 0160 } 0161 0162 KAddressBookImportExport::ContactList contactLists; 0163 contactLists.setAddressList(contacts); 0164 QFileDialog::Options options = QFileDialog::DontConfirmOverwrite; 0165 QUrl url = QFileDialog::getSaveFileUrl(parentWidget(), QString(), QUrl::fromLocalFile(QStringLiteral("addressbook.csv")), QString(), nullptr, options); 0166 if (url.isEmpty()) { 0167 return; 0168 } 0169 0170 if (QFileInfo::exists(url.isLocalFile() ? url.toLocalFile() : url.path())) { 0171 if (url.isLocalFile() && QFileInfo::exists(url.toLocalFile())) { 0172 auto dialog = new PimCommon::RenameFileDialog(url, false, parentWidget()); 0173 auto result = static_cast<PimCommon::RenameFileDialog::RenameFileDialogResult>(dialog->exec()); 0174 if (result == PimCommon::RenameFileDialog::RENAMEFILE_RENAME) { 0175 url = dialog->newName(); 0176 } else if (result == PimCommon::RenameFileDialog::RENAMEFILE_IGNORE) { 0177 delete dialog; 0178 return; 0179 } 0180 delete dialog; 0181 } 0182 } 0183 0184 if (!url.isLocalFile()) { 0185 QTemporaryFile tmpFile; 0186 if (!tmpFile.open()) { 0187 const QString msg = i18n("<qt>Unable to open file <b>%1</b></qt>", url.url()); 0188 KMessageBox::error(parentWidget(), msg); 0189 return; 0190 } 0191 exportToFile(&tmpFile, contactLists.addressList()); 0192 tmpFile.flush(); 0193 auto job = KIO::file_copy(QUrl::fromLocalFile(tmpFile.fileName()), url, -1, KIO::Overwrite); 0194 KJobWidgets::setWindow(job, parentWidget()); 0195 job->exec(); 0196 } else { 0197 QFile file(url.toLocalFile()); 0198 if (!file.open(QIODevice::WriteOnly)) { 0199 const QString msg = i18n("<qt>Unable to open file <b>%1</b>.</qt>", url.toLocalFile()); 0200 KMessageBox::error(parentWidget(), msg); 0201 return; 0202 } 0203 0204 exportToFile(&file, contactLists.addressList()); 0205 file.close(); 0206 } 0207 } 0208 0209 bool CSVImportExportPluginInterface::canImportFileType(const QUrl &url) 0210 { 0211 return url.path().endsWith(QLatin1StringView(".csv")); 0212 } 0213 0214 void CSVImportExportPluginInterface::importFile(const QUrl &url) 0215 { 0216 // TODO 0217 Q_UNUSED(url) 0218 } 0219 0220 #include "moc_csvimportexportplugininterface.cpp"