This repository has been archived on 2023-10-09. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
blender-archive/source/blender/editors/asset/asset_ops.cc
Julian Eisel 04be1e9980 Code quality: Refactor asset operators using C++
* Attempt to improve readability by using focused, coherent helper classes.
* Replace ListBase with blender::Vector, which is more efficient and has a
  better API.
* Split user reporting from error checking.
* Use namespace (as we usually do for C++ code).
* Remove unused headers
2021-02-08 10:32:18 +01:00

260 lines
6.4 KiB
C++

/*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
/** \file
* \ingroup edasset
*/
#include "BKE_context.h"
#include "BKE_report.h"
#include "BLI_vector.hh"
#include "ED_asset.h"
#include "RNA_access.h"
#include "WM_api.h"
#include "WM_types.h"
/* -------------------------------------------------------------------- */
using PointerRNAVec = blender::Vector<PointerRNA>;
static bool asset_operation_poll(bContext * /*C*/)
{
return U.experimental.use_asset_browser;
}
/**
* Return the IDs to operate on as PointerRNA vector. Either a single one ("id" context member) or
* multiple ones ("selected_ids" context member).
*/
static PointerRNAVec asset_operation_get_ids_from_context(const bContext *C)
{
PointerRNAVec ids;
PointerRNA idptr = CTX_data_pointer_get_type(C, "id", &RNA_ID);
if (idptr.data) {
/* Single ID. */
ids.append(idptr);
}
else {
ListBase list;
CTX_data_selected_ids(C, &list);
LISTBASE_FOREACH (CollectionPointerLink *, link, &list) {
ids.append(link->ptr);
}
BLI_freelistN(&list);
}
return ids;
}
/* -------------------------------------------------------------------- */
class AssetMarkHelper {
public:
void operator()(const bContext &C, PointerRNAVec &ids);
void reportResults(ReportList &reports) const;
bool wasSuccessful() const;
private:
struct Stats {
int tot_created = 0;
int tot_already_asset = 0;
ID *last_id = nullptr;
};
Stats stats;
};
void AssetMarkHelper::operator()(const bContext &C, PointerRNAVec &ids)
{
for (PointerRNA &ptr : ids) {
BLI_assert(RNA_struct_is_ID(ptr.type));
ID *id = static_cast<ID *>(ptr.data);
if (id->asset_data) {
stats.tot_already_asset++;
continue;
}
if (ED_asset_mark_id(&C, id)) {
stats.last_id = id;
stats.tot_created++;
}
}
}
bool AssetMarkHelper::wasSuccessful() const
{
return stats.tot_created > 0;
}
void AssetMarkHelper::reportResults(ReportList &reports) const
{
/* User feedback on failure. */
if (!wasSuccessful()) {
if ((stats.tot_already_asset > 0)) {
BKE_report(&reports,
RPT_ERROR,
"Selected data-blocks are already assets (or do not support use as assets)");
}
else {
BKE_report(&reports,
RPT_ERROR,
"No data-blocks to create assets for found (or do not support use as assets)");
}
}
/* User feedback on success. */
else if (stats.tot_created == 1) {
/* If only one data-block: Give more useful message by printing asset name. */
BKE_reportf(&reports, RPT_INFO, "Data-block '%s' is now an asset", stats.last_id->name + 2);
}
else {
BKE_reportf(&reports, RPT_INFO, "%i data-blocks are now assets", stats.tot_created);
}
}
static int asset_mark_exec(bContext *C, wmOperator *op)
{
PointerRNAVec ids = asset_operation_get_ids_from_context(C);
AssetMarkHelper mark_helper;
mark_helper(*C, ids);
mark_helper.reportResults(*op->reports);
if (!mark_helper.wasSuccessful()) {
return OPERATOR_CANCELLED;
}
WM_main_add_notifier(NC_ID | NA_EDITED, nullptr);
WM_main_add_notifier(NC_ASSET | NA_ADDED, nullptr);
return OPERATOR_FINISHED;
}
static void ASSET_OT_mark(wmOperatorType *ot)
{
ot->name = "Mark Asset";
ot->description =
"Enable easier reuse of selected data-blocks through the Asset Browser, with the help of "
"customizable metadata (like previews, descriptions and tags)";
ot->idname = "ASSET_OT_mark";
ot->exec = asset_mark_exec;
ot->poll = asset_operation_poll;
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
/* -------------------------------------------------------------------- */
class AssetClearHelper {
public:
void operator()(PointerRNAVec &ids);
void reportResults(ReportList &reports) const;
bool wasSuccessful() const;
private:
struct Stats {
int tot_cleared = 0;
ID *last_id = nullptr;
};
Stats stats;
};
void AssetClearHelper::operator()(PointerRNAVec &ids)
{
for (PointerRNA &ptr : ids) {
BLI_assert(RNA_struct_is_ID(ptr.type));
ID *id = static_cast<ID *>(ptr.data);
if (!id->asset_data) {
continue;
}
if (ED_asset_clear_id(id)) {
stats.tot_cleared++;
stats.last_id = id;
}
}
}
void AssetClearHelper::reportResults(ReportList &reports) const
{
if (!wasSuccessful()) {
BKE_report(&reports, RPT_ERROR, "No asset data-blocks selected/focused");
}
else if (stats.tot_cleared == 1) {
/* If only one data-block: Give more useful message by printing asset name. */
BKE_reportf(
&reports, RPT_INFO, "Data-block '%s' is no asset anymore", stats.last_id->name + 2);
}
else {
BKE_reportf(&reports, RPT_INFO, "%i data-blocks are no assets anymore", stats.tot_cleared);
}
}
bool AssetClearHelper::wasSuccessful() const
{
return stats.tot_cleared > 0;
}
static int asset_clear_exec(bContext *C, wmOperator *op)
{
PointerRNAVec ids = asset_operation_get_ids_from_context(C);
AssetClearHelper clear_helper;
clear_helper(ids);
clear_helper.reportResults(*op->reports);
if (!clear_helper.wasSuccessful()) {
return OPERATOR_CANCELLED;
}
WM_main_add_notifier(NC_ID | NA_EDITED, nullptr);
WM_main_add_notifier(NC_ASSET | NA_REMOVED, nullptr);
return OPERATOR_FINISHED;
}
static void ASSET_OT_clear(wmOperatorType *ot)
{
ot->name = "Clear Asset";
ot->description =
"Delete all asset metadata and turn the selected asset data-blocks back into normal "
"data-blocks";
ot->idname = "ASSET_OT_clear";
ot->exec = asset_clear_exec;
ot->poll = asset_operation_poll;
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
/* -------------------------------------------------------------------- */
void ED_operatortypes_asset(void)
{
WM_operatortype_append(ASSET_OT_mark);
WM_operatortype_append(ASSET_OT_clear);
}