mirror of
https://github.com/altlinux/admc.git
synced 2025-02-13 17:57:25 +03:00
change members tab to apply non-instantly
repurpose move dialog to select dialog, renamed in next commit move object moving and adding to group outside of move dialog \ to object context menu
This commit is contained in:
parent
44c0ba6bc6
commit
89a21240c6
@ -75,6 +75,7 @@ set(ADMC_SOURCES
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/rename_dialog.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/create_dialog.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/attribute_display_strings.cpp
|
||||
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/edits/attribute_edit.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/edits/string_edit.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/edits/country_edit.cpp
|
||||
|
@ -1354,3 +1354,17 @@ int bit_set(int bitmask, int bit, bool set) {
|
||||
bool bit_is_set(int bitmask, int bit) {
|
||||
return ((bitmask & bit) != 0);
|
||||
}
|
||||
|
||||
QString object_class_display_string(const QString &object_class) {
|
||||
static const QHash<QString, QString> strings = {
|
||||
{CLASS_CONTAINER, QObject::tr("Container")},
|
||||
{CLASS_OU, QObject::tr("OU")},
|
||||
{CLASS_GROUP, QObject::tr("Group")},
|
||||
{CLASS_USER, QObject::tr("User")}
|
||||
};
|
||||
const QString default_value = object_class;
|
||||
|
||||
const QString display_string = strings.value(object_class, default_value);
|
||||
|
||||
return display_string;
|
||||
}
|
||||
|
@ -244,5 +244,6 @@ QString datetime_raw_to_display_string(const QString &attribute, const QString &
|
||||
QDateTime datetime_raw_to_datetime(const QString &attribute, const QString &raw_value);
|
||||
QString group_scope_to_string(GroupScope scope);
|
||||
QString group_type_to_string(GroupType type);
|
||||
QString object_class_display_string(const QString &c);
|
||||
|
||||
#endif /* AD_INTERFACE_H */
|
||||
|
@ -39,9 +39,6 @@ public:
|
||||
virtual bool verify() = 0;
|
||||
virtual void apply() = 0;
|
||||
|
||||
signals:
|
||||
void edited();
|
||||
|
||||
public slots:
|
||||
void on_edit_changed();
|
||||
|
||||
|
@ -21,9 +21,18 @@
|
||||
#include "object_context_menu.h"
|
||||
#include "utils.h"
|
||||
#include "dn_column_proxy.h"
|
||||
#include "move_dialog.h"
|
||||
|
||||
#include <QTreeView>
|
||||
#include <QVBoxLayout>
|
||||
#include <QStandardItemModel>
|
||||
#include <QMenu>
|
||||
#include <QPushButton>
|
||||
|
||||
// Store members in a set
|
||||
// Generate model from current members list
|
||||
// Add new members via select dialog
|
||||
// Remove through context menu or select+remove button
|
||||
|
||||
enum MembersColumn {
|
||||
MembersColumn_Name,
|
||||
@ -36,40 +45,73 @@ MembersTab::MembersTab(ObjectContextMenu *object_context_menu, DetailsWidget *de
|
||||
{
|
||||
view = new QTreeView(this);
|
||||
view->setEditTriggers(QAbstractItemView::NoEditTriggers);
|
||||
view->setAcceptDrops(true);
|
||||
view->setContextMenuPolicy(Qt::CustomContextMenu);
|
||||
view->setDragDropMode(QAbstractItemView::DragDrop);
|
||||
view->setAllColumnsShowFocus(true);
|
||||
view->setSortingEnabled(true);
|
||||
object_context_menu->connect_view(view, MembersColumn_DN);
|
||||
|
||||
model = new MembersModel(this);
|
||||
model = new QStandardItemModel(0, MembersColumn_COUNT, this);
|
||||
model->setHorizontalHeaderItem(MembersColumn_Name, new QStandardItem(tr("Name")));
|
||||
model->setHorizontalHeaderItem(MembersColumn_DN, new QStandardItem(tr("DN")));
|
||||
|
||||
const auto dn_column_proxy = new DnColumnProxy(MembersColumn_DN, this);
|
||||
|
||||
setup_model_chain(view, model, {dn_column_proxy});
|
||||
|
||||
const auto layout = new QVBoxLayout(this);
|
||||
|
||||
auto add_button = new QPushButton(tr("Add"));
|
||||
auto remove_button = new QPushButton(tr("Remove"));
|
||||
auto button_layout = new QHBoxLayout();
|
||||
button_layout->addWidget(add_button);
|
||||
button_layout->addWidget(remove_button);
|
||||
|
||||
const auto layout = new QVBoxLayout();
|
||||
setLayout(layout);
|
||||
layout->setContentsMargins(0, 0, 0, 0);
|
||||
layout->setSpacing(0);
|
||||
layout->addWidget(view);
|
||||
layout->addLayout(button_layout);
|
||||
|
||||
connect(
|
||||
remove_button, &QAbstractButton::clicked,
|
||||
this, &MembersTab::on_remove_button);
|
||||
connect(
|
||||
add_button, &QAbstractButton::clicked,
|
||||
this, &MembersTab::on_add_button);
|
||||
QObject::connect(
|
||||
view, &QWidget::customContextMenuRequested,
|
||||
this, &MembersTab::on_context_menu);
|
||||
}
|
||||
|
||||
bool MembersTab::changed() const {
|
||||
return false;
|
||||
return (current_members != original_members);
|
||||
}
|
||||
|
||||
bool MembersTab::verify() {
|
||||
return true;
|
||||
}
|
||||
|
||||
// TODO: could do this with less requests by deleting all values of ATTRIBUTE_MEMBER and then setting to the list of values, but need to implement this in adldap
|
||||
void MembersTab::apply() {
|
||||
for (auto member : original_members) {
|
||||
const bool removed = !current_members.contains(member);
|
||||
if (removed) {
|
||||
AdInterface::instance()->attribute_delete(target(), ATTRIBUTE_MEMBER, member);
|
||||
}
|
||||
}
|
||||
|
||||
for (auto member : current_members) {
|
||||
const bool added = !original_members.contains(member);
|
||||
if (added) {
|
||||
AdInterface::instance()->attribute_add(target(), ATTRIBUTE_MEMBER, member);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MembersTab::reload() {
|
||||
model->change_target(target());
|
||||
const QList<QString> members = AdInterface::instance()->attribute_get_multi(target(), ATTRIBUTE_MEMBER);
|
||||
original_members = members.toSet();
|
||||
current_members = original_members;
|
||||
|
||||
set_root_to_head(view);
|
||||
load_current_members_into_model();
|
||||
}
|
||||
|
||||
bool MembersTab::accepts_target() const {
|
||||
@ -78,37 +120,84 @@ bool MembersTab::accepts_target() const {
|
||||
return is_group;
|
||||
}
|
||||
|
||||
MembersModel::MembersModel(QObject *parent)
|
||||
: ObjectModel(MembersColumn_COUNT, MembersColumn_DN, parent)
|
||||
{
|
||||
setHorizontalHeaderItem(MembersColumn_Name, new QStandardItem(tr("Name")));
|
||||
setHorizontalHeaderItem(MembersColumn_DN, new QStandardItem(tr("DN")));
|
||||
// TODO: similar to code in ObjectContextMenu
|
||||
void MembersTab::on_context_menu(const QPoint pos) {
|
||||
const QModelIndex base_index = view->indexAt(pos);
|
||||
if (!base_index.isValid()) {
|
||||
return;
|
||||
}
|
||||
const QModelIndex index = convert_to_source(base_index);
|
||||
const QString dn = get_dn_from_index(index, MembersColumn_DN);
|
||||
|
||||
const QPoint global_pos = view->mapToGlobal(pos);
|
||||
|
||||
auto menu = new QMenu(this);
|
||||
QAction *remove_action = menu->addAction(tr("Remove from group"));
|
||||
connect(
|
||||
remove_action, &QAction::triggered,
|
||||
[this, dn]() {
|
||||
const QList<QString> removed_members = {dn};
|
||||
remove_members(removed_members);
|
||||
});
|
||||
menu->popup(global_pos);
|
||||
}
|
||||
|
||||
void MembersModel::change_target(const QString &dn) {
|
||||
removeRows(0, rowCount());
|
||||
void MembersTab::on_add_button() {
|
||||
const QList<QString> classes = {CLASS_USER};
|
||||
const QList<QString> selected_objects = MoveDialog::open(classes, MoveDialogMultiSelection_Yes);
|
||||
|
||||
auto create_row = [this](const QString &row_dn) {
|
||||
if (selected_objects.size() > 0) {
|
||||
add_members(selected_objects);
|
||||
}
|
||||
}
|
||||
|
||||
void MembersTab::on_remove_button() {
|
||||
const QItemSelectionModel *selection_model = view->selectionModel();
|
||||
const QList<QModelIndex> selected = selection_model->selectedIndexes();
|
||||
|
||||
QList<QString> removed_members;
|
||||
for (auto index : selected) {
|
||||
const QModelIndex converted = convert_to_source(index);
|
||||
const QString dn = get_dn_from_index(converted, MembersColumn_DN);
|
||||
|
||||
removed_members.append(dn);
|
||||
}
|
||||
|
||||
remove_members(removed_members);
|
||||
}
|
||||
|
||||
void MembersTab::load_current_members_into_model() {
|
||||
model->removeRows(0, model->rowCount());
|
||||
|
||||
for (auto dn : current_members) {
|
||||
QList<QStandardItem *> row;
|
||||
for (int i = 0; i < MembersColumn_COUNT; i++) {
|
||||
row.append(new QStandardItem());
|
||||
}
|
||||
const QString name = AdInterface::instance()->attribute_get(row_dn, ATTRIBUTE_NAME);
|
||||
const QString name = extract_name_from_dn(dn);
|
||||
row[MembersColumn_Name]->setText(name);
|
||||
row[MembersColumn_DN]->setText(row_dn);
|
||||
row[MembersColumn_DN]->setText(dn);
|
||||
|
||||
return row;
|
||||
};
|
||||
|
||||
// Create root item to represent group itself
|
||||
QList<QStandardItem *> group_row = create_row(dn);
|
||||
appendRow(group_row);
|
||||
QStandardItem *group_item = group_row[0];
|
||||
|
||||
// Populate model with members of new root
|
||||
const QList<QString> members = AdInterface::instance()->attribute_get_multi(dn, ATTRIBUTE_MEMBER);
|
||||
for (auto member_dn : members) {
|
||||
QList<QStandardItem *> member_row = create_row(member_dn);
|
||||
group_item->appendRow(member_row);
|
||||
model->appendRow(row);
|
||||
}
|
||||
}
|
||||
|
||||
void MembersTab::add_members(QList<QString> members) {
|
||||
for (auto member : members) {
|
||||
current_members.insert(member);
|
||||
}
|
||||
|
||||
load_current_members_into_model();
|
||||
|
||||
on_edit_changed();
|
||||
}
|
||||
|
||||
void MembersTab::remove_members(QList<QString> members) {
|
||||
for (auto member : members) {
|
||||
current_members.remove(member);
|
||||
}
|
||||
|
||||
load_current_members_into_model();
|
||||
|
||||
on_edit_changed();
|
||||
}
|
||||
|
@ -23,11 +23,17 @@
|
||||
#include "details_tab.h"
|
||||
#include "object_model.h"
|
||||
|
||||
#include <QPoint>
|
||||
#include <QSet>
|
||||
#include <QString>
|
||||
|
||||
class QTreeView;
|
||||
class QString;
|
||||
class ObjectContextMenu;
|
||||
class MembersModel;
|
||||
|
||||
class QStandardItemModel;
|
||||
|
||||
// Shows member objects of targeted group
|
||||
class MembersTab final : public DetailsTab {
|
||||
Q_OBJECT
|
||||
@ -36,18 +42,21 @@ public:
|
||||
MembersTab(ObjectContextMenu *object_context_menu, DetailsWidget *details_arg);
|
||||
DECL_DETAILS_TAB_VIRTUALS();
|
||||
|
||||
private slots:
|
||||
void on_context_menu(const QPoint pos);
|
||||
void on_add_button();
|
||||
void on_remove_button();
|
||||
|
||||
private:
|
||||
MembersModel *model = nullptr;
|
||||
// MembersModel *model = nullptr;
|
||||
QStandardItemModel *model = nullptr;
|
||||
QTreeView *view = nullptr;
|
||||
};
|
||||
QSet<QString> original_members;
|
||||
QSet<QString> current_members;
|
||||
|
||||
class MembersModel final : public ObjectModel {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
MembersModel(QObject *parent);
|
||||
|
||||
void change_target(const QString &dn);
|
||||
void load_current_members_into_model();
|
||||
void add_members(QList<QString> members);
|
||||
void remove_members(QList<QString> members);
|
||||
};
|
||||
|
||||
#endif /* MEMBERS_TAB_H */
|
||||
|
@ -20,7 +20,6 @@
|
||||
#include "move_dialog.h"
|
||||
#include "ad_interface.h"
|
||||
#include "settings.h"
|
||||
#include "confirmation_dialog.h"
|
||||
#include "dn_column_proxy.h"
|
||||
#include "utils.h"
|
||||
|
||||
@ -30,10 +29,9 @@
|
||||
#include <QTreeView>
|
||||
#include <QSortFilterProxyModel>
|
||||
#include <QComboBox>
|
||||
#include <QAction>
|
||||
#include <QPushButton>
|
||||
#include <QItemSelectionModel>
|
||||
#include <QList>
|
||||
#include <QStandardItemModel>
|
||||
|
||||
enum MoveDialogColumn {
|
||||
MoveDialogColumn_Name,
|
||||
@ -42,15 +40,15 @@ enum MoveDialogColumn {
|
||||
MoveDialogColumn_COUNT
|
||||
};
|
||||
|
||||
const QMap<ClassFilter, QString> class_filter_string = {
|
||||
{ClassFilter_All, ""},
|
||||
{ClassFilter_Containers, CLASS_CONTAINER},
|
||||
{ClassFilter_OUs, CLASS_OU},
|
||||
{ClassFilter_Groups, CLASS_GROUP},
|
||||
};
|
||||
QList<QString> MoveDialog::open(QList<QString> classes, MoveDialogMultiSelection multi_selection) {
|
||||
MoveDialog dialog(classes, multi_selection);
|
||||
dialog.exec();
|
||||
|
||||
MoveDialog::MoveDialog(QWidget *parent)
|
||||
: QDialog(parent)
|
||||
return dialog.selected_objects;
|
||||
}
|
||||
|
||||
MoveDialog::MoveDialog(QList<QString> classes, MoveDialogMultiSelection multi_selection)
|
||||
: QDialog()
|
||||
{
|
||||
resize(600, 600);
|
||||
|
||||
@ -58,13 +56,17 @@ MoveDialog::MoveDialog(QWidget *parent)
|
||||
view->setEditTriggers(QAbstractItemView::NoEditTriggers);
|
||||
view->setSortingEnabled(true);
|
||||
|
||||
target_label = new QLabel(tr("TARGET"), this);
|
||||
if (multi_selection == MoveDialogMultiSelection_Yes) {
|
||||
view->setSelectionMode(QAbstractItemView::MultiSelection);
|
||||
}
|
||||
|
||||
filter_class_label = new QLabel(tr("Class: "), this);
|
||||
filter_class_combo_box = new QComboBox(this);
|
||||
auto target_label = new QLabel(tr("Select object"), this);
|
||||
|
||||
auto filter_class_label = new QLabel(tr("Class: "), this);
|
||||
auto filter_class_combo = new QComboBox(this);
|
||||
|
||||
const auto filter_name_label = new QLabel(tr("Name: "), this);
|
||||
filter_name_line_edit = new QLineEdit(this);
|
||||
auto filter_name_edit = new QLineEdit(this);
|
||||
|
||||
const auto select_button = new QPushButton(tr("Select"), this);
|
||||
const auto cancel_button = new QPushButton(tr("Cancel"), this);
|
||||
@ -72,199 +74,28 @@ MoveDialog::MoveDialog(QWidget *parent)
|
||||
const auto layout = new QGridLayout(this);
|
||||
layout->addWidget(target_label, 0, 0);
|
||||
layout->addWidget(filter_class_label, 1, 0, Qt::AlignRight);
|
||||
layout->addWidget(filter_class_combo_box, 1, 1, 1, 2);
|
||||
layout->addWidget(filter_class_combo, 1, 1, 1, 2);
|
||||
layout->addWidget(filter_name_label, 2, 0, Qt::AlignRight);
|
||||
layout->addWidget(filter_name_line_edit, 2, 1, 1, 2);
|
||||
layout->addWidget(filter_name_edit, 2, 1, 1, 2);
|
||||
layout->addWidget(view, 3, 0, 1, 3);
|
||||
layout->addWidget(cancel_button, 4, 0, Qt::AlignLeft);
|
||||
layout->addWidget(select_button, 4, 2, Qt::AlignRight);
|
||||
|
||||
model = new MoveDialogModel(this);
|
||||
|
||||
proxy_name = new QSortFilterProxyModel(this);
|
||||
auto proxy_name = new QSortFilterProxyModel(this);
|
||||
proxy_name->setFilterKeyColumn(MoveDialogColumn_Name);
|
||||
|
||||
proxy_class = new QSortFilterProxyModel(this);
|
||||
auto proxy_class = new QSortFilterProxyModel(this);
|
||||
proxy_class->setFilterKeyColumn(MoveDialogColumn_Class);
|
||||
|
||||
const auto dn_column_proxy = new DnColumnProxy(MoveDialogColumn_DN, this);
|
||||
|
||||
setup_model_chain(view, model, {proxy_name, proxy_class, dn_column_proxy});
|
||||
|
||||
connect(
|
||||
view, &QAbstractItemView::doubleClicked,
|
||||
this, &MoveDialog::on_double_clicked);
|
||||
connect(
|
||||
filter_name_line_edit, &QLineEdit::textChanged,
|
||||
this, &MoveDialog::on_filter_name_changed);
|
||||
connect(filter_class_combo_box, QOverload<int>::of(&QComboBox::currentIndexChanged),
|
||||
this, &MoveDialog::on_filter_class_changed);
|
||||
connect(
|
||||
select_button, &QAbstractButton::clicked,
|
||||
this, &MoveDialog::on_select_button);
|
||||
connect(
|
||||
cancel_button, &QAbstractButton::clicked,
|
||||
this, &MoveDialog::on_cancel_button);
|
||||
connect(
|
||||
this, &QDialog::finished,
|
||||
model, &MoveDialogModel::on_dialog_finished);
|
||||
}
|
||||
|
||||
void MoveDialog::open_for_object(const QString &dn, MoveDialogType type_arg) {
|
||||
target_dn = dn;
|
||||
type = type_arg;
|
||||
|
||||
filter_name_line_edit->setText("");
|
||||
on_filter_name_changed("");
|
||||
|
||||
QString target_label_text;
|
||||
switch (type) {
|
||||
case MoveDialogType_Move: {
|
||||
target_label_text = QString(tr("Moving \"%1\"")).arg(target_dn);
|
||||
break;
|
||||
}
|
||||
case MoveDialogType_AddToGroup: {
|
||||
target_label_text = QString(tr("Adding \"%1\" to group")).arg(target_dn);
|
||||
break;
|
||||
}
|
||||
}
|
||||
target_label->setText(target_label_text);
|
||||
|
||||
// Select classes that this object can be moved to
|
||||
// TODO: cover all cases
|
||||
QList<ClassFilter> classes;
|
||||
switch (type) {
|
||||
case MoveDialogType_Move: {
|
||||
const bool is_container = AdInterface::instance()->is_container(dn);
|
||||
if (is_container) {
|
||||
classes = {ClassFilter_Containers};
|
||||
} else {
|
||||
classes = {ClassFilter_Containers, ClassFilter_OUs};
|
||||
}
|
||||
break;
|
||||
}
|
||||
case MoveDialogType_AddToGroup: {
|
||||
classes = {ClassFilter_Groups};
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Fill class combo box with possible classes and "All" option
|
||||
filter_class_combo_box->clear();
|
||||
QList<ClassFilter> combo_classes = {ClassFilter_All};
|
||||
combo_classes += classes;
|
||||
for (auto c : combo_classes) {
|
||||
auto filter_display_string =
|
||||
[] (ClassFilter filter) {
|
||||
switch (filter) {
|
||||
case ClassFilter_All: return MoveDialog::tr("All");
|
||||
case ClassFilter_Containers: return MoveDialog::tr("Containers");
|
||||
case ClassFilter_OUs: return MoveDialog::tr("OU's");
|
||||
case ClassFilter_Groups: return MoveDialog::tr("Groups");
|
||||
case ClassFilter_COUNT: return QString("COUNT");
|
||||
}
|
||||
return QString("");
|
||||
};
|
||||
|
||||
const QString display_string = filter_display_string(c);
|
||||
|
||||
filter_class_combo_box->addItem(display_string, c);
|
||||
}
|
||||
|
||||
// Show or hide class-related elements depending on type
|
||||
switch (type) {
|
||||
case MoveDialogType_Move: {
|
||||
filter_class_combo_box->show();
|
||||
filter_class_label->show();
|
||||
view->setColumnHidden(MoveDialogColumn_Class, false);
|
||||
|
||||
break;
|
||||
}
|
||||
case MoveDialogType_AddToGroup: {
|
||||
filter_class_combo_box->hide();
|
||||
filter_class_label->hide();
|
||||
view->setColumnHidden(MoveDialogColumn_Class, true);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
model->load(dn, classes);
|
||||
|
||||
for (int col = 0; col < view->model()->columnCount(); col++) {
|
||||
view->resizeColumnToContents(col);
|
||||
}
|
||||
|
||||
open();
|
||||
}
|
||||
|
||||
void MoveDialog::on_filter_name_changed(const QString &text) {
|
||||
proxy_name->setFilterRegExp(QRegExp(text, Qt::CaseInsensitive, QRegExp::FixedString));
|
||||
}
|
||||
|
||||
void MoveDialog::on_filter_class_changed(int index) {
|
||||
const QVariant item_data = filter_class_combo_box->itemData(index);
|
||||
const ClassFilter class_filter = item_data.value<ClassFilter>();
|
||||
const QString regexp = class_filter_string[class_filter];
|
||||
|
||||
proxy_class->setFilterRegExp(QRegExp(regexp, Qt::CaseInsensitive, QRegExp::FixedString));
|
||||
}
|
||||
|
||||
void MoveDialog::complete(const QString &move_dn) {
|
||||
const QString confirm_text = QString(tr("Move \"%1\" to \"%2\"?")).arg(target_dn, move_dn);
|
||||
|
||||
const bool confirmed = confirmation_dialog(confirm_text, this);
|
||||
if (confirmed) {
|
||||
switch (type) {
|
||||
case MoveDialogType_Move: {
|
||||
AdInterface::instance()->object_move(target_dn, move_dn);
|
||||
break;
|
||||
}
|
||||
case MoveDialogType_AddToGroup: {
|
||||
AdInterface::instance()->group_add_user(move_dn, target_dn);
|
||||
break;
|
||||
}
|
||||
}
|
||||
done(QDialog::Accepted);
|
||||
}
|
||||
}
|
||||
|
||||
void MoveDialog::on_select_button(bool) {
|
||||
const QItemSelectionModel *selection_model = view->selectionModel();
|
||||
if (!selection_model->hasSelection()) {
|
||||
return;
|
||||
}
|
||||
const QModelIndex selected_index = selection_model->currentIndex();
|
||||
const QString move_dn = get_dn_from_index(selected_index, MoveDialogColumn_DN);
|
||||
|
||||
complete(move_dn);
|
||||
}
|
||||
|
||||
void MoveDialog::on_double_clicked(const QModelIndex &index) {
|
||||
const QString move_dn = get_dn_from_index(index, MoveDialogColumn_DN);
|
||||
|
||||
complete(move_dn);
|
||||
}
|
||||
|
||||
void MoveDialog::on_cancel_button(bool) {
|
||||
done(QDialog::Rejected);
|
||||
}
|
||||
|
||||
|
||||
|
||||
MoveDialogModel::MoveDialogModel(QObject *parent)
|
||||
: QStandardItemModel(0, MoveDialogColumn_COUNT, parent)
|
||||
{
|
||||
setHorizontalHeaderItem(MoveDialogColumn_Name, new QStandardItem(tr("Name")));
|
||||
setHorizontalHeaderItem(MoveDialogColumn_Class, new QStandardItem(tr("Class")));
|
||||
setHorizontalHeaderItem(MoveDialogColumn_DN, new QStandardItem(tr("DN")));
|
||||
}
|
||||
|
||||
void MoveDialogModel::load(const QString &dn, QList<ClassFilter> classes) {
|
||||
for (auto c : classes) {
|
||||
const QString class_string = class_filter_string[c];
|
||||
|
||||
QString filter = filter_EQUALS(ATTRIBUTE_OBJECT_CLASS, class_string);
|
||||
// Load model
|
||||
auto model = new QStandardItemModel(0, MoveDialogColumn_COUNT, this);
|
||||
model->setHorizontalHeaderItem(MoveDialogColumn_Name, new QStandardItem(tr("Name")));
|
||||
model->setHorizontalHeaderItem(MoveDialogColumn_Class, new QStandardItem(tr("Class")));
|
||||
model->setHorizontalHeaderItem(MoveDialogColumn_DN, new QStandardItem(tr("DN")));
|
||||
for (auto object_class : classes) {
|
||||
QString filter = filter_EQUALS(ATTRIBUTE_OBJECT_CLASS, object_class);
|
||||
|
||||
// Filter out advanced objects if needed
|
||||
const bool advanced_view = Settings::instance()->get_bool(BoolSetting_AdvancedView);
|
||||
@ -287,14 +118,78 @@ void MoveDialogModel::load(const QString &dn, QList<ClassFilter> classes) {
|
||||
const QString name = extract_name_from_dn(e_dn);
|
||||
|
||||
row[MoveDialogColumn_Name]->setText(name);
|
||||
row[MoveDialogColumn_Class]->setText(class_string);
|
||||
row[MoveDialogColumn_Class]->setText(object_class);
|
||||
row[MoveDialogColumn_DN]->setText(e_dn);
|
||||
|
||||
appendRow(row);
|
||||
model->appendRow(row);
|
||||
}
|
||||
}
|
||||
|
||||
setup_model_chain(view, model, {proxy_name, proxy_class, dn_column_proxy});
|
||||
|
||||
// Fill class combo box with possible classes
|
||||
filter_class_combo->clear();
|
||||
for (auto object_class : classes) {
|
||||
auto display_string = object_class_display_string(object_class);
|
||||
|
||||
filter_class_combo->addItem(display_string, object_class);
|
||||
}
|
||||
|
||||
// Disable/hide class-related elements if selecting only from one class
|
||||
if (classes.size() == 1) {
|
||||
filter_class_combo->setEnabled(false);
|
||||
view->setColumnHidden(MoveDialogColumn_Class, true);
|
||||
}
|
||||
|
||||
for (int col = 0; col < view->model()->columnCount(); col++) {
|
||||
view->resizeColumnToContents(col);
|
||||
}
|
||||
|
||||
// Disable select button when there's no selection and enable when there is
|
||||
const QItemSelectionModel *selection_model = view->selectionModel();
|
||||
connect(selection_model, &QItemSelectionModel::selectionChanged,
|
||||
[selection_model, select_button]() {
|
||||
const bool enable_select_button = selection_model->hasSelection();
|
||||
select_button->setEnabled(enable_select_button);
|
||||
});
|
||||
|
||||
// Update proxy name when filter name changes
|
||||
connect(
|
||||
filter_name_edit, &QLineEdit::textChanged,
|
||||
[proxy_name](const QString &text) {
|
||||
proxy_name->setFilterRegExp(QRegExp(text, Qt::CaseInsensitive, QRegExp::FixedString));
|
||||
});
|
||||
filter_name_edit->setText("");
|
||||
|
||||
// Update proxy class when filter class changes
|
||||
connect(filter_class_combo, QOverload<int>::of(&QComboBox::currentIndexChanged),
|
||||
[filter_class_combo, proxy_class](const int index) {
|
||||
const QVariant item_data = filter_class_combo->itemData(index);
|
||||
const QString object_class = item_data.toString();
|
||||
|
||||
proxy_class->setFilterRegExp(QRegExp(object_class, Qt::CaseInsensitive, QRegExp::FixedString));
|
||||
});
|
||||
|
||||
connect(
|
||||
select_button, &QAbstractButton::clicked,
|
||||
this, &QDialog::accept);
|
||||
connect(
|
||||
cancel_button, &QAbstractButton::clicked,
|
||||
this, &QDialog::reject);
|
||||
}
|
||||
|
||||
void MoveDialogModel::on_dialog_finished(int) {
|
||||
removeRows(0, rowCount());
|
||||
void MoveDialog::accept() {
|
||||
const QItemSelectionModel *selection_model = view->selectionModel();
|
||||
const QList<QModelIndex> selected_indexes = selection_model->selectedIndexes();
|
||||
|
||||
selected_objects.clear();
|
||||
for (auto index : selected_indexes) {
|
||||
const QString dn = get_dn_from_index(index, MoveDialogColumn_DN);
|
||||
|
||||
if (!selected_objects.contains(dn)) {
|
||||
selected_objects.append(dn);
|
||||
}
|
||||
}
|
||||
|
||||
QDialog::accept();
|
||||
}
|
||||
|
@ -22,72 +22,29 @@
|
||||
|
||||
#include <QDialog>
|
||||
#include <QString>
|
||||
#include <QStandardItemModel>
|
||||
#include <QList>
|
||||
|
||||
class QWidget;
|
||||
class QLineEdit;
|
||||
class QSortFilterProxyModel;
|
||||
class QComboBox;
|
||||
class MoveDialogModel;
|
||||
class QTreeView;
|
||||
class QLabel;
|
||||
class QAction;
|
||||
|
||||
enum MoveDialogType {
|
||||
MoveDialogType_Move,
|
||||
MoveDialogType_AddToGroup
|
||||
enum MoveDialogMultiSelection {
|
||||
MoveDialogMultiSelection_Yes,
|
||||
MoveDialogMultiSelection_No
|
||||
};
|
||||
|
||||
enum ClassFilter {
|
||||
ClassFilter_All,
|
||||
ClassFilter_Containers,
|
||||
ClassFilter_OUs,
|
||||
ClassFilter_Groups,
|
||||
ClassFilter_COUNT
|
||||
};
|
||||
Q_DECLARE_METATYPE(ClassFilter)
|
||||
|
||||
class MoveDialog final : public QDialog {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
MoveDialog(QWidget *parent);
|
||||
|
||||
void open_for_object(const QString &dn, MoveDialogType type);
|
||||
static QList<QString> open(QList<QString> classes, MoveDialogMultiSelection multi_selection = MoveDialogMultiSelection_No);
|
||||
|
||||
private slots:
|
||||
void on_filter_name_changed(const QString &text);
|
||||
void on_filter_class_changed(int index);
|
||||
void on_select_button(bool checked);
|
||||
void on_cancel_button(bool checked);
|
||||
void on_double_clicked(const QModelIndex &index);
|
||||
void accept();
|
||||
|
||||
private:
|
||||
QTreeView *view = nullptr;
|
||||
QLabel *target_label = nullptr;
|
||||
QLabel *filter_class_label = nullptr;
|
||||
QComboBox *filter_class_combo_box = nullptr;
|
||||
QLineEdit *filter_name_line_edit = nullptr;
|
||||
MoveDialogModel *model = nullptr;
|
||||
QSortFilterProxyModel *proxy_name = nullptr;
|
||||
QSortFilterProxyModel *proxy_class = nullptr;
|
||||
QString target_dn = "";
|
||||
MoveDialogType type;
|
||||
QTreeView *view;
|
||||
QList<QString> selected_objects;
|
||||
|
||||
void complete(const QString &move_dn);
|
||||
};
|
||||
|
||||
class MoveDialogModel final : public QStandardItemModel {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
MoveDialogModel(QObject *parent);
|
||||
|
||||
void load(const QString &dn, QList<ClassFilter> classes);
|
||||
|
||||
public slots:
|
||||
void on_dialog_finished(int);
|
||||
MoveDialog(QList<QString> classes, MoveDialogMultiSelection multi_selection);
|
||||
};
|
||||
|
||||
#endif /* MOVE_DIALOG_H */
|
||||
|
@ -41,8 +41,6 @@ void force_reload_attributes_and_diff(const QString &dn);
|
||||
ObjectContextMenu::ObjectContextMenu(QWidget *parent)
|
||||
: QMenu(parent)
|
||||
{
|
||||
// NOTE: use parent, not context menu itself so dialog is centered
|
||||
move_dialog = new MoveDialog(parent);
|
||||
}
|
||||
|
||||
// Open this context menu when view requests one
|
||||
@ -98,13 +96,16 @@ void ObjectContextMenu::open(const QPoint &global_pos, const QString &dn, const
|
||||
});
|
||||
}
|
||||
|
||||
addAction(tr("Move"), [this, dn]() {
|
||||
move_dialog->open_for_object(dn, MoveDialogType_Move);
|
||||
});
|
||||
QAction *move_action = addAction(tr("Move"));
|
||||
connect(
|
||||
move_action, &QAction::triggered,
|
||||
[this, dn]() {
|
||||
move(dn);
|
||||
});
|
||||
|
||||
const bool is_policy = AdInterface::instance()->is_policy(dn);
|
||||
const bool is_user = AdInterface::instance()->is_user(dn);
|
||||
|
||||
|
||||
if (is_policy) {
|
||||
submenu_new->addAction(tr("Edit Policy"), [this, dn]() {
|
||||
edit_policy(dn);
|
||||
@ -112,9 +113,12 @@ void ObjectContextMenu::open(const QPoint &global_pos, const QString &dn, const
|
||||
}
|
||||
|
||||
if (is_user) {
|
||||
addAction(tr("Add to group"), [this, dn]() {
|
||||
move_dialog->open_for_object(dn, MoveDialogType_AddToGroup);
|
||||
});
|
||||
QAction *add_to_group_action = addAction(tr("Add to group"));
|
||||
connect(
|
||||
add_to_group_action, &QAction::triggered,
|
||||
[this, dn]() {
|
||||
add_to_group(dn);
|
||||
});
|
||||
|
||||
addAction(tr("Reset password"), [this, dn]() {
|
||||
const auto password_dialog = new PasswordDialog(dn, this);
|
||||
@ -187,6 +191,36 @@ void ObjectContextMenu::edit_policy(const QString &dn) {
|
||||
process->start();
|
||||
}
|
||||
|
||||
void ObjectContextMenu::move(const QString &dn) {
|
||||
// TODO: somehow formalize "class X can only be moved to X,Y,Z..." better
|
||||
const bool is_container = AdInterface::instance()->is_container(dn);
|
||||
QList<QString> classes;
|
||||
if (is_container) {
|
||||
classes = {CLASS_CONTAINER};
|
||||
} else {
|
||||
classes = {CLASS_CONTAINER, CLASS_OU};
|
||||
}
|
||||
|
||||
const QList<QString> selected_objects = MoveDialog::open(classes);
|
||||
|
||||
if (selected_objects.size() == 1) {
|
||||
const QString container = selected_objects[0];
|
||||
|
||||
AdInterface::instance()->object_move(dn, container);
|
||||
}
|
||||
}
|
||||
|
||||
void ObjectContextMenu::add_to_group(const QString &dn) {
|
||||
const QList<QString> classes = {CLASS_GROUP};
|
||||
const QList<QString> selected_objects = MoveDialog::open(classes, MoveDialogMultiSelection_Yes);
|
||||
|
||||
if (selected_objects.size() > 0) {
|
||||
for (auto group : selected_objects) {
|
||||
AdInterface::instance()->group_add_user(group, dn);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void force_reload_attributes_and_diff(const QString &dn) {
|
||||
|
||||
QMap<QString, QList<QString>> old_attributes = AdInterface::instance()->get_all_attributes(dn);
|
||||
|
@ -39,13 +39,13 @@ public:
|
||||
|
||||
signals:
|
||||
void details(const QString &dn);
|
||||
|
||||
|
||||
private:
|
||||
MoveDialog *move_dialog = nullptr;
|
||||
|
||||
void open(const QPoint &global_pos, const QString &dn, const QString &parent_dn);
|
||||
void delete_object(const QString &dn);
|
||||
void edit_policy(const QString &dn);
|
||||
void move(const QString &dn);
|
||||
void add_to_group(const QString &dn);
|
||||
|
||||
};
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user