File indexing completed on 2024-04-28 05:11:37

0001 /*
0002  * SPDX-FileCopyrightText: 2014 Sandro Knauß <knauss@kolabsys.com>
0003  *
0004  * SPDX-License-Identifier: GPL-2.0-or-later WITH Qt-Commercial-exception-1.0
0005  */
0006 
0007 #include "resourcemanagement.h"
0008 #include "ldaputils.h"
0009 #include "resourcemodel.h"
0010 #include "ui_resourcemanagement.h"
0011 #include <CalendarSupport/FreeBusyItem>
0012 
0013 #include <Akonadi/FreeBusyManager>
0014 
0015 #include <EventViews/AgendaView>
0016 
0017 #include <KCalendarCore/Event>
0018 
0019 #include <KConfigGroup>
0020 #include <KLocalizedString>
0021 #include <KSharedConfig>
0022 
0023 #include <KWindowConfig>
0024 #include <QColor>
0025 #include <QDialogButtonBox>
0026 #include <QLabel>
0027 #include <QPushButton>
0028 #include <QStringList>
0029 #include <QWindow>
0030 
0031 using namespace IncidenceEditorNG;
0032 namespace
0033 {
0034 static const char myResourceManagementConfigGroupName[] = "ResourceManagement";
0035 }
0036 class FreebusyViewCalendar : public EventViews::ViewCalendar
0037 {
0038 public:
0039     ~FreebusyViewCalendar() override = default;
0040 
0041     [[nodiscard]] bool isValid(const KCalendarCore::Incidence::Ptr &incidence) const override
0042     {
0043         return isValid(incidence->uid());
0044     }
0045 
0046     [[nodiscard]] bool isValid(const QString &incidenceIdentifier) const override
0047     {
0048         return incidenceIdentifier.startsWith(QLatin1StringView("fb-"));
0049     }
0050 
0051     [[nodiscard]] QString displayName(const KCalendarCore::Incidence::Ptr &incidence) const override
0052     {
0053         Q_UNUSED(incidence)
0054         return QStringLiteral("Freebusy");
0055     }
0056 
0057     [[nodiscard]] QColor resourceColor(const KCalendarCore::Incidence::Ptr &incidence) const override
0058     {
0059         bool ok = false;
0060         int status = incidence->customProperty(QStringLiteral("FREEBUSY").toLatin1(), QStringLiteral("STATUS").toLatin1()).toInt(&ok);
0061 
0062         if (!ok) {
0063             return {85, 85, 85};
0064         }
0065 
0066         switch (status) {
0067         case KCalendarCore::FreeBusyPeriod::Busy:
0068             return {255, 0, 0};
0069         case KCalendarCore::FreeBusyPeriod::BusyTentative:
0070         case KCalendarCore::FreeBusyPeriod::BusyUnavailable:
0071             return {255, 119, 0};
0072         case KCalendarCore::FreeBusyPeriod::Free:
0073             return {0, 255, 0};
0074         default:
0075             return {85, 85, 85};
0076         }
0077     }
0078 
0079     [[nodiscard]] QString iconForIncidence(const KCalendarCore::Incidence::Ptr &incidence) const override
0080     {
0081         Q_UNUSED(incidence)
0082         return {};
0083     }
0084 
0085     [[nodiscard]] KCalendarCore::Calendar::Ptr getCalendar() const override
0086     {
0087         return mCalendar;
0088     }
0089 
0090     KCalendarCore::Calendar::Ptr mCalendar;
0091 };
0092 
0093 ResourceManagement::ResourceManagement(QWidget *parent)
0094     : QDialog(parent)
0095 {
0096     setWindowTitle(i18nc("@title:window", "Resource Management"));
0097     auto buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Close, this);
0098     QPushButton *okButton = buttonBox->button(QDialogButtonBox::Ok);
0099     okButton->setDefault(true);
0100     okButton->setShortcut(Qt::CTRL | Qt::Key_Return);
0101     okButton->setText(i18nc("@action:button add resource to attendeelist", "Book resource"));
0102 
0103     connect(buttonBox, &QDialogButtonBox::accepted, this, &ResourceManagement::accept);
0104     connect(buttonBox, &QDialogButtonBox::rejected, this, &ResourceManagement::reject);
0105 
0106     mUi = new Ui_resourceManagement;
0107 
0108     auto w = new QWidget(this);
0109     mUi->setupUi(w);
0110     auto mainLayout = new QVBoxLayout(this);
0111     mainLayout->addWidget(w);
0112 
0113     mainLayout->addWidget(buttonBox);
0114 
0115     mModel = new CalendarSupport::FreeBusyItemModel(this);
0116     mFreebusyCalendar.setModel(mModel);
0117 
0118     mAgendaView = new EventViews::AgendaView(QDate(), QDate(), false, false);
0119 
0120     auto fbCalendar = new FreebusyViewCalendar();
0121     fbCalendar->mCalendar = mFreebusyCalendar.calendar();
0122     mFbCalendar = EventViews::ViewCalendar::Ptr(fbCalendar);
0123     mAgendaView->addCalendar(mFbCalendar);
0124 
0125     mUi->resourceCalender->addWidget(mAgendaView);
0126 
0127     QStringList attrs;
0128     attrs << QStringLiteral("cn") << QStringLiteral("mail") << QStringLiteral("owner") << QStringLiteral("givenname") << QStringLiteral("sn")
0129           << QStringLiteral("kolabDescAttribute") << QStringLiteral("description");
0130     auto resourcemodel = new ResourceModel(attrs, this);
0131     mUi->treeResults->setModel(resourcemodel);
0132 
0133     // This doesn't work till now :(-> that's why i use the click signal
0134     mUi->treeResults->setSelectionMode(QAbstractItemView::SingleSelection);
0135     selectionModel = mUi->treeResults->selectionModel();
0136 
0137     connect(mUi->resourceSearch, &QLineEdit::textChanged, this, &ResourceManagement::slotStartSearch);
0138 
0139     connect(mUi->treeResults, &QTreeView::clicked, this, &ResourceManagement::slotShowDetails);
0140 
0141     connect(resourcemodel, &ResourceModel::layoutChanged, this, &ResourceManagement::slotLayoutChanged);
0142     readConfig();
0143 }
0144 
0145 ResourceManagement::~ResourceManagement()
0146 {
0147     writeConfig();
0148     delete mModel;
0149     delete mUi;
0150 }
0151 
0152 void ResourceManagement::readConfig()
0153 {
0154     create(); // ensure a window is created
0155     windowHandle()->resize(QSize(600, 400));
0156     KConfigGroup group(KSharedConfig::openStateConfig(), QLatin1StringView(myResourceManagementConfigGroupName));
0157     KWindowConfig::restoreWindowSize(windowHandle(), group);
0158     resize(windowHandle()->size()); // workaround for QTBUG-40584
0159 }
0160 
0161 void ResourceManagement::writeConfig()
0162 {
0163     KConfigGroup group(KSharedConfig::openStateConfig(), QLatin1StringView(myResourceManagementConfigGroupName));
0164     KWindowConfig::saveWindowSize(windowHandle(), group);
0165     group.sync();
0166 }
0167 
0168 ResourceItem::Ptr ResourceManagement::selectedItem() const
0169 {
0170     return mSelectedItem;
0171 }
0172 
0173 void ResourceManagement::slotStartSearch(const QString &text)
0174 {
0175     (static_cast<ResourceModel *>(mUi->treeResults->model()))->startSearch(text);
0176 }
0177 
0178 void ResourceManagement::slotShowDetails(const QModelIndex &current)
0179 {
0180     auto item = current.model()->data(current, ResourceModel::Resource).value<ResourceItem::Ptr>();
0181     mSelectedItem = item;
0182     showDetails(item->ldapObject(), item->ldapClient());
0183 }
0184 
0185 void ResourceManagement::showDetails(const KLDAPCore::LdapObject &obj, const KLDAPWidgets::LdapClient &client)
0186 {
0187     // Clean up formDetails
0188     QLayoutItem *child = nullptr;
0189     while ((child = mUi->formDetails->takeAt(0)) != nullptr) {
0190         delete child->widget();
0191         delete child;
0192     }
0193     mUi->groupOwner->setHidden(true);
0194 
0195     // Fill formDetails with data
0196     for (auto it = obj.attributes().cbegin(), end = obj.attributes().cbegin(); it != end; ++it) {
0197         const QString &key = it.key();
0198         if (key == QLatin1StringView("objectClass") || key == QLatin1StringView("email")) {
0199             continue;
0200         } else if (key == QLatin1StringView("owner")) {
0201             QStringList attrs;
0202             attrs << QStringLiteral("cn") << QStringLiteral("mail") << QStringLiteral("mobile") << QStringLiteral("telephoneNumber")
0203                   << QStringLiteral("kolabDescAttribute") << QStringLiteral("description");
0204             mOwnerItem = ResourceItem::Ptr(new ResourceItem(KLDAPCore::LdapDN(QString::fromUtf8(it.value().at(0))), attrs, client));
0205             connect(mOwnerItem.data(), &ResourceItem::searchFinished, this, &ResourceManagement::slotOwnerSearchFinished);
0206             mOwnerItem->startSearch();
0207             continue;
0208         }
0209         QStringList list;
0210         const QList<QByteArray> values = it.value();
0211         list.reserve(values.count());
0212         for (const QByteArray &value : values) {
0213             list << QString::fromUtf8(value);
0214         }
0215         mUi->formDetails->addRow(translateLDAPAttributeForDisplay(key), new QLabel(list.join(QLatin1Char('\n'))));
0216     }
0217 
0218     QString name = QString::fromUtf8(obj.attributes().value(QStringLiteral("cn"))[0]);
0219     QString email = QString::fromUtf8(obj.attributes().value(QStringLiteral("mail"))[0]);
0220     KCalendarCore::Attendee attendee(name, email);
0221     CalendarSupport::FreeBusyItem::Ptr freebusy(new CalendarSupport::FreeBusyItem(attendee, this));
0222     mModel->clear();
0223     mModel->addItem(freebusy);
0224 }
0225 
0226 void ResourceManagement::slotLayoutChanged()
0227 {
0228     const int columnCount = mUi->treeResults->model()->columnCount(QModelIndex());
0229     for (int i = 1; i < columnCount; ++i) {
0230         mUi->treeResults->setColumnHidden(i, true);
0231     }
0232 }
0233 
0234 void ResourceManagement::slotOwnerSearchFinished()
0235 {
0236     // Clean up formDetails
0237     QLayoutItem *child = nullptr;
0238     while ((child = mUi->formOwner->takeAt(0)) != nullptr) {
0239         delete child->widget();
0240         delete child;
0241     }
0242     mUi->groupOwner->setHidden(false);
0243 
0244     const KLDAPCore::LdapObject &obj = mOwnerItem->ldapObject();
0245     const KLDAPCore::LdapAttrMap &ldapAttrMap = obj.attributes();
0246     for (auto it = ldapAttrMap.cbegin(), end = ldapAttrMap.cend(); it != end; ++it) {
0247         const QString &key = it.key();
0248         if (key == QLatin1StringView("objectClass") || key == QLatin1StringView("owner") || key == QLatin1StringView("givenname")
0249             || key == QLatin1StringView("sn")) {
0250             continue;
0251         }
0252         QStringList list;
0253         const QList<QByteArray> values = it.value();
0254         list.reserve(values.count());
0255         for (const QByteArray &value : values) {
0256             list << QString::fromUtf8(value);
0257         }
0258         mUi->formOwner->addRow(translateLDAPAttributeForDisplay(key), new QLabel(list.join(QLatin1Char('\n'))));
0259     }
0260 }
0261 
0262 void ResourceManagement::slotDateChanged(const QDate &start, const QDate &end)
0263 {
0264     if (start.daysTo(end) < 7) {
0265         mAgendaView->showDates(start, start.addDays(7));
0266     }
0267     mAgendaView->showDates(start, end);
0268 }
0269 
0270 #include "moc_resourcemanagement.cpp"