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 ¤t) 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"