Remove Nepomuk, Convert QJSon to Qt5, fix wrong url conversion, fixes xml effects and luma files

parent 720f643b
......@@ -8,7 +8,6 @@ find_package(OpenGL REQUIRED)
if(APPLE)
find_package(SDL REQUIRED)
endif(APPLE)
find_package(QJSON)
option(WITH_JogShuttle "Build Jog/Shuttle support" ON)
......@@ -55,13 +54,6 @@ set_package_properties(QtScript PROPERTIES
# )
#endif(APPLE)
set_package_properties(QJson PROPERTIES
DESCRIPTION "Qt module providing core scripting facilities"
URL "http://qjson.sourceforge.net"
TYPE RUNTIME
PURPOSE "Required to build the rotoscoping filter and for Freesound.org queries")
install(FILES kdenlivesettings.kcfg DESTINATION ${KCFG_INSTALL_DIR})
kconfig_add_kcfg_files(kdenlive_SRCS kdenlivesettings.kcfgc)
......@@ -81,10 +73,7 @@ add_subdirectory(simplekeyframes)
add_subdirectory(stopmotion)
add_subdirectory(titler)
add_subdirectory(utils)
if(QJSON_FOUND)
add_subdirectory(onmonitoritems/rotoscoping)
endif(QJSON_FOUND)
add_subdirectory(onmonitoritems/rotoscoping)
list(APPEND kdenlive_SRCS
colortools.cpp
......@@ -272,31 +261,6 @@ if(SDL_FOUND)
target_link_libraries(kdenlive ${SDL_LIBRARY})
endif(SDL_FOUND)
if(NepomukCore_FOUND)
add_definitions(-DUSE_NEPOMUKCORE)
include_directories(${NEPOMUK_CORE_INCLUDE_DIR})
target_link_libraries(kdenlive ${NEPOMUK_CORE_LIBRARY})
# Nepomuk Core does not bring in the Soprano includes it needs
find_package(Soprano)
macro_log_feature(Soprano_FOUND "Soprano libraries"
"RDF storage, parsing, and serialization framework"
"http://soprano.sourceforge.net/" TRUE ""
"Required by Nepomuk Core Libraries")
include_directories(${SOPRANO_INCLUDE_DIR})
else()
if(Nepomuk_FOUND)
add_definitions(-DUSE_NEPOMUK)
include_directories(${NEPOMUK_INCLUDES})
target_link_libraries(kdenlive ${NEPOMUK_LIBRARIES})
endif(Nepomuk_FOUND)
endif()
if(QJSON_FOUND)
add_definitions(-DUSE_QJSON)
include_directories(${QJSON_INCLUDE_DIR})
target_link_libraries(kdenlive ${QJSON_LIBRARIES})
endif(QJSON_FOUND)
if(LIBV4L2_FOUND)
include_directories(${LIBV4L2_INCLUDE_DIR})
target_link_libraries(kdenlive ${LIBV4L2_LIBRARY})
......
......@@ -71,10 +71,11 @@ void initEffects::refreshLumas()
QStringList customLumas = QStandardPaths::locateAll(QStandardPaths::DataLocation, "lumas");
foreach(const QString & folder, customLumas) {
QStringList filesnames = QDir(folder).entryList(filters, QDir::Files);
QDir directory(folder);
QStringList filesnames = directory.entryList(filters, QDir::Files);
foreach(const QString & fname, filesnames) {
imagenamelist.append(fname);
imagefiles.append(QUrl(folder).path() + QDir::separator() + fname);
imagefiles.append(directory.absoluteFilePath(fname));
}
}
......@@ -84,8 +85,7 @@ void initEffects::refreshLumas()
QStringList filesnames = lumafolder.entryList(filters, QDir::Files);
foreach(const QString & fname, filesnames) {
imagenamelist.append(fname);
QFileInfo f(folder.path(), fname);
imagefiles.append(f.filePath());
imagefiles.append(lumafolder.absoluteFilePath(fname));
}
QDomElement lumaTransition = MainWindow::transitions.getEffectByTag("luma", "luma");
QDomNodeList params = lumaTransition.elementsByTagName("parameter");
......@@ -249,7 +249,7 @@ void initEffects::parseEffectFiles(const QString &locale)
}
// Set the directories to look into for effects.
QStringList direc = QStandardPaths::locateAll(QStandardPaths::DataLocation, "effects");
QStringList direc = QStandardPaths::locateAll(QStandardPaths::DataLocation, "effects", QStandardPaths::LocateDirectory);
// Iterate through effects directories to parse all XML files.
for (more = direc.begin(); more != direc.end(); ++more) {
QDir directory(*more);
......@@ -257,7 +257,7 @@ void initEffects::parseEffectFiles(const QString &locale)
filter << "*.xml";
fileList = directory.entryList(filter, QDir::Files);
for (it = fileList.begin(); it != fileList.end(); ++it) {
itemName = QUrl(*more + *it).path();
itemName = directory.absoluteFilePath(*it);
parseEffectFile(&MainWindow::customEffects,
&MainWindow::audioEffects,
&MainWindow::videoEffects,
......@@ -324,7 +324,7 @@ void initEffects::parseCustomEffectsFile()
QDomElement e;
int unknownGroupCount = 0;
foreach(const QString & filename, fileList) {
QString itemName = QUrl(path + filename).path();
QString itemName = directory.absoluteFilePath(filename);
QFile file(itemName);
doc.setContent(&file, false);
file.close();
......@@ -569,8 +569,7 @@ void initEffects::fillTransitionsList(Mlt::Repository *repository, EffectsList *
QStringList filesnames = lumafolder.entryList(filters, QDir::Files);
foreach(const QString & fname, filesnames) {
imagenamelist.append(fname);
QFileInfo f(folder.path(), fname);
imagefiles.append(f.filePath());
imagefiles.append(lumafolder.absoluteFilePath(fname));
}
//WARNING: this is a hack to get around temporary invalid metadata in MLT, 2nd of june 2011 JBM
......
......@@ -37,9 +37,7 @@
#include "dialogs/profilesdialog.h"
#include "project/projectlist.h"
#include "timeline/customtrackview.h"
#ifdef USE_QJSON
#include "onmonitoritems/rotoscoping/rotowidget.h"
#endif
#include "ui_listval_ui.h"
#include "ui_boolval_ui.h"
......@@ -351,16 +349,14 @@ ParameterContainer::ParameterContainer(const QDomElement &effect, const ItemInfo
QString depends = pa.attribute("depends");
if (!depends.isEmpty())
meetDependency(paramName, type, EffectsList::parameter(e, depends));
#ifdef USE_QJSON
} else if (type == "roto-spline") {
m_needsMonitorEffectScene = true;
RotoWidget *roto = new RotoWidget(value, m_metaInfo->monitor, info, m_metaInfo->timecode, parent);
RotoWidget *roto = new RotoWidget(value.toLatin1(), m_metaInfo->monitor, info, m_metaInfo->timecode, parent);
connect(roto, SIGNAL(valueChanged()), this, SLOT(slotCollectAllParameters()));
connect(roto, SIGNAL(seekToPos(int)), this, SIGNAL(seekTimeline(int)));
connect(this, SIGNAL(syncEffectsPos(int)), roto, SLOT(slotSyncPosition(int)));
m_vbox->addWidget(roto);
m_valueItems[paramName] = roto;
#endif
} else if (type == "wipe") {
Wipeval *wpval = new Wipeval;
wpval->setupUi(toFillin);
......@@ -583,11 +579,9 @@ void ParameterContainer::updateTimecodeFormat()
PositionEdit *posi = static_cast<PositionEdit*>(m_valueItems[paramName+"position"]);
posi->updateTimecodeFormat();
break;
#ifdef USE_QJSON
} else if (type == "roto-spline") {
RotoWidget *widget = static_cast<RotoWidget *>(m_valueItems[paramName]);
widget->updateTimecodeFormat();
#endif
}
}
}
......@@ -698,11 +692,9 @@ void ParameterContainer::slotCollectAllParameters()
QString depends = pa.attribute("depends");
if (!depends.isEmpty())
meetDependency(paramName, type, EffectsList::parameter(m_effect, depends));
#ifdef USE_QJSON
} else if (type == "roto-spline") {
RotoWidget *widget = static_cast<RotoWidget *>(m_valueItems.value(paramName));
setValue = widget->getSpline();
#endif
} else if (type == "wipe") {
Wipeval *wp = static_cast<Wipeval*>(m_valueItems.value(paramName));
wipeInfo info;
......
......@@ -192,7 +192,6 @@ void MonitorScene::mousePressEvent(QGraphicsSceneMouseEvent* event)
void MonitorScene::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
{
if (m_groupMove) {
#ifdef USE_QJSON
// we want to move multiple items
// rotoscoping only for now
QPointF diff = event->scenePos() - m_lastPos;
......@@ -222,7 +221,6 @@ void MonitorScene::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
}
}
}
#endif
} else {
QGraphicsScene::mouseMoveEvent(event);
}
......@@ -231,7 +229,6 @@ void MonitorScene::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
void MonitorScene::mouseReleaseEvent(QGraphicsSceneMouseEvent* event)
{
if (m_groupMove) {
#ifdef USE_QJSON
QList <QGraphicsItem *> selected = selectedItems();
foreach (QGraphicsItem *item, selected) {
if (qgraphicsitem_cast<BPointItem*>(item) && item->parentItem()) {
......@@ -243,7 +240,6 @@ void MonitorScene::mouseReleaseEvent(QGraphicsSceneMouseEvent* event)
}
}
m_groupMove = false;
#endif
}
QGraphicsScene::mouseReleaseEvent(event);
m_view->setDragMode(QGraphicsView::NoDrag);
......
......@@ -28,12 +28,9 @@
#include "kdenlivesettings.h"
#include <mlt++/Mlt.h>
#include <math.h>
#include <qjson/parser.h>
#include <qjson/serializer.h>
#include <QJsonDocument>
#include <QVBoxLayout>
/** @brief Listener for "tracking-finished" event in MLT rotoscoping filter. */
......@@ -42,10 +39,10 @@ void tracking_finished(mlt_service *owner, RotoWidget *self, char *data)
Q_UNUSED(owner)
if (self)
self->setSpline(QString(data));
self->setSpline(QByteArray(data));
}
RotoWidget::RotoWidget(const QString &data, Monitor *monitor, const ItemInfo &info, const Timecode &t, QWidget* parent) :
RotoWidget::RotoWidget(const QByteArray &data, Monitor *monitor, const ItemInfo &info, const Timecode &t, QWidget* parent) :
QWidget(parent),
m_monitor(monitor),
m_in(info.cropStart.frames(KdenliveSettings::project_fps())),
......@@ -140,10 +137,10 @@ void RotoWidget::slotUpdateData(bool editing)
slotUpdateData(-1, editing);
}
QString RotoWidget::getSpline()
QByteArray RotoWidget::getSpline()
{
QJson::Serializer serializer;
return QString(serializer.serialize(m_data));
QJsonDocument doc = QJsonDocument::fromVariant(m_data);
return doc.toJson();
}
void RotoWidget::slotPositionChanged(int pos, bool seek)
......@@ -355,12 +352,12 @@ void RotoWidget::setupTrackingListen(const ItemInfo &info)
delete clip;
}
void RotoWidget::setSpline(const QString &spline, bool notify)
void RotoWidget::setSpline(const QByteArray &spline, bool notify)
{
QJson::Parser parser;
bool ok;
m_data = parser.parse(spline.simplified().toUtf8(), &ok);
if (!ok) {
QJsonParseError jsonError;
QJsonDocument doc = QJsonDocument::fromJson(spline, &jsonError);
m_data = doc.toVariant();
if (jsonError.error) {
// :(
}
keyframeTimelineFullUpdate();
......@@ -396,16 +393,15 @@ static QVariant interpolate(int position, int in, int out, QVariant *splineIn, Q
return QVariant(keyframe);
}
bool adjustRotoDuration(QString* data, int in, int out)
bool adjustRotoDuration(QByteArray* data, int in, int out)
{
QJson::Parser parser;
bool ok;
QVariant splines = parser.parse(data->toUtf8(), &ok);
if (!ok) {
*data = QString();
QJsonParseError jsonError;
QJsonDocument doc = QJsonDocument::fromJson(*data, &jsonError);
if (jsonError.error) {
*data = QByteArray();
return true;
}
QVariant splines = doc.toVariant();
if (!splines.canConvert(QVariant::Map))
return false;
......@@ -464,8 +460,8 @@ bool adjustRotoDuration(QString* data, int in, int out)
++i;
}
QJson::Serializer serializer;
*data = QString(serializer.serialize(QVariant(newMap)));
doc = QJsonDocument::fromVariant(QVariant(newMap));
*data = doc.toJson();
if (startFound || endFound)
return true;
......
......@@ -35,21 +35,21 @@ class Filter;
}
/** @brief Adjusts keyframes after resizing a clip. */
bool adjustRotoDuration(QString *data, int in, int out);
bool adjustRotoDuration(QByteArray *data, int in, int out);
class RotoWidget : public QWidget
{
Q_OBJECT
public:
RotoWidget(const QString &data, Monitor *monitor, const ItemInfo &info, const Timecode &t, QWidget* parent = 0);
RotoWidget(const QByteArray &data, Monitor *monitor, const ItemInfo &info, const Timecode &t, QWidget* parent = 0);
~RotoWidget();
/** @brief Returns the spline(s) in the JSON format used by filter_rotoscoping (MLT). */
QString getSpline();
QByteArray getSpline();
/** @brief Replaces current data with \param spline (JSON). */
void setSpline(const QString &spline, bool notify = true);
void setSpline(const QByteArray &spline, bool notify = true);
/** @brief Passed on to the keyframe timeline. Switches between frames and hh:mm:ss:ff timecode. */
void updateTimecodeFormat();
......
......@@ -32,22 +32,6 @@
#include <QDebug>
#include <QFontDatabase>
#ifdef USE_NEPOMUK
#if KDE_IS_VERSION(4,6,0)
#include <Nepomuk/Variant>
#include <Nepomuk/Resource>
#include <Nepomuk/ResourceManager>
#include <Nepomuk/Vocabulary/NIE>
#endif
#endif
#ifdef USE_NEPOMUKCORE
#include <Nepomuk2/Variant>
#include <Nepomuk2/Resource>
#include <Nepomuk2/ResourceManager>
#include <Nepomuk2/Vocabulary/NIE>
#endif
#include <QDir>
#include <QPainter>
#include <QFileDialog>
......@@ -503,51 +487,6 @@ ClipProperties::ClipProperties(DocClipBase *clip, const Timecode &tc, double fps
m_view.analysis_load->setToolTip(i18n("Load analysis data"));
m_view.analysis_save->setIcon(QIcon::fromTheme("document-save-as"));
m_view.analysis_save->setToolTip(i18n("Save analysis data"));
// Check for Nepomuk metadata
#ifdef USE_NEPOMUK
#if KDE_IS_VERSION(4,6,0)
if (url.isValid()) {
Nepomuk::ResourceManager::instance()->init();
Nepomuk::Resource res( url.path() );
// Check if file has a license
if (res.hasProperty(Nepomuk::Vocabulary::NIE::license())) {
QString ltype = res.property(Nepomuk::Vocabulary::NIE::licenseType()).toString();
m_view.clip_license->setText(i18n("License: %1", res.property(Nepomuk::Vocabulary::NIE::license()).toString()));
if (ltype.startsWith(QLatin1String("http"))) {
m_view.clip_license->setUrl(ltype);
connect(m_view.clip_license, SIGNAL(leftClickedUrl(QString)), this, SLOT(slotOpenUrl(QString)));
}
}
else m_view.clip_license->setHidden(true);
}
else m_view.clip_license->setHidden(true);
#else
m_view.clip_license->setHidden(true);
#endif
#else
#ifdef USE_NEPOMUKCORE
if (url.isValid()) {
Nepomuk2::ResourceManager::instance()->init();
Nepomuk2::Resource res( url.path() );
// Check if file has a license
if (res.hasProperty(Nepomuk2::Vocabulary::NIE::license())) {
QString ltype = res.property(Nepomuk2::Vocabulary::NIE::licenseType()).toString();
m_view.clip_license->setText(i18n("License: %1", res.property(Nepomuk2::Vocabulary::NIE::license()).toString()));
if (ltype.startsWith(QLatin1String("http"))) {
m_view.clip_license->setUrl(ltype);
connect(m_view.clip_license, SIGNAL(leftClickedUrl(QString)), this, SLOT(slotOpenUrl(QString)));
}
}
else m_view.clip_license->setHidden(true);
}
else m_view.clip_license->setHidden(true);
#else
m_view.clip_license->setHidden(true);
#endif
#endif
slotFillMarkersList(m_clip);
slotUpdateAnalysisData(m_clip);
......
......@@ -57,19 +57,6 @@
#include <QHBoxLayout>
#include <KPassivePopup>
#ifdef USE_NEPOMUK
#include <nepomuk/global.h>
#include <nepomuk/resourcemanager.h>
#include <Nepomuk/Resource>
//#include <nepomuk/tag.h>
#endif
#ifdef USE_NEPOMUKCORE
#include <nepomuk2/resourcemanager.h>
#include <Nepomuk2/Resource>
#endif
#include <QAction>
#include <QPixmap>
#include <QMenu>
......@@ -299,26 +286,6 @@ ProjectList::ProjectList(QWidget *parent) :
m_listView->setItemDelegate(m_listViewDelegate);
m_clipPropertiesManager = new ClipPropertiesManager(this);
#ifdef USE_NEPOMUK
if (KdenliveSettings::activate_nepomuk()) {
Nepomuk::ResourceManager::instance()->init();
if (!Nepomuk::ResourceManager::instance()->initialized()) {
//qDebug() << "Cannot communicate with Nepomuk, DISABLING it";
KdenliveSettings::setActivate_nepomuk(false);
}
}
#endif
#ifdef USE_NEPOMUKCORE
if (KdenliveSettings::activate_nepomuk()) {
Nepomuk2::ResourceManager::instance()->init();
if (!Nepomuk2::ResourceManager::instance()->initialized()) {
//qDebug() << "Cannot communicate with Nepomuk, DISABLING it";
KdenliveSettings::setActivate_nepomuk(false);
}
}
#endif
}
ProjectList::~ProjectList()
......@@ -981,23 +948,6 @@ void ProjectList::slotUpdateClipProperties(ProjectItem *clip, QMap <QString, QSt
emit clipNameChanged(clip->clipId(), properties.value("name"));
}
if (properties.contains("description")) {
#ifdef USE_NEPOMUK
ClipType type = clip->clipType();
#endif
monitorItemEditing(false);
clip->setText(1, properties.value("description"));
monitorItemEditing(true);
#ifdef USE_NEPOMUK
bool hasType = (type == Audio || type == Video || type == AV ||
type == Image || type == Playlist);
if (KdenliveSettings::activate_nepomuk() && hasType) {
// Use Nepomuk system to store clip description
Nepomuk::Resource f(clip->clipUrl().path());
f.setDescription(properties.value("description"));
}
#endif
emit projectModified();
}
}
......@@ -1347,18 +1297,6 @@ void ProjectList::slotAddClip(DocClipBase *clip, bool getProperties)
}*/
QUrl url = clip->fileURL();
#ifdef USE_NEPOMUK
if (url.isValid() && KdenliveSettings::activate_nepomuk() && clip->getProperty("description").isEmpty()) {
// if file has Nepomuk comment, use it
Nepomuk::Resource f(url.path());
QString annotation = f.description();
if (!annotation.isEmpty()) {
item->setText(1, annotation);
clip->setProperty("description", annotation);
}
item->setText(2, QString::number(f.rating()));
}
#endif
// Add info to date column
QFileInfo fileInfo(url.path());
......
......@@ -498,22 +498,6 @@ void ItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option,
}
painter->restore();
} else if (index.column() == 2 && KdenliveSettings::activate_nepomuk()) {
if (index.data().toString().isEmpty()) {
QStyledItemDelegate::paint(painter, option, index);
return;
}
QRect r1 = option.rect;
if (option.state & (QStyle::State_Selected)) {
painter->fillRect(r1, option.palette.highlight());
}
#ifdef NEPOMUK
KRatingPainter::paintRating(painter, r1, Qt::AlignCenter, index.data().toInt());
#endif
#ifdef NEPOMUKCORE
KRatingPainter::paintRating(painter, r1, Qt::AlignCenter, index.data().toInt());
#endif
} else {
QStyledItemDelegate::paint(painter, option, index);
}
......
......@@ -28,9 +28,7 @@
#include "doc/kthumb.h"
#include "doc/docclipbase.h"
#include "dialogs/profilesdialog.h"
#ifdef USE_QJSON
#include "onmonitoritems/rotoscoping/rotowidget.h"
#endif
#include <QDebug>
#include <QIcon>
......@@ -2050,14 +2048,12 @@ QMap<int, QDomElement> ClipItem::adjustEffectsToDuration(int width, int height,
if (!effects.contains(i))
effects[i] = effect.cloneNode().toElement();
updateNormalKeyframes(param, oldInfo);
#ifdef USE_QJSON
} else if (type == "roto-spline") {
if (!effects.contains(i))
effects[i] = effect.cloneNode().toElement();
QString value = param.attribute("value");
QByteArray value = param.attribute("value").toLatin1();
if (adjustRotoDuration(&value, cropStart().frames(m_fps), (cropStart() + cropDuration()).frames(m_fps) - 1))
param.setAttribute("value", value);
#endif
param.setAttribute("value", QString(value));
}
}
}
......
......@@ -45,26 +45,6 @@
#include <KPixmapSequenceOverlayPainter>
#include <KFileItem>
#ifdef USE_NEPOMUK
#if KDE_IS_VERSION(4,6,0)
#include <Nepomuk/Variant>
#include <Nepomuk/Resource>
#include <Nepomuk/ResourceManager>
#include <Nepomuk/Vocabulary/NIE>
#include <Nepomuk/Vocabulary/NCO>
#include <Nepomuk/Vocabulary/NDO>
#endif
#endif
#ifdef USE_NEPOMUKCORE
#include <Nepomuk2/Variant>
#include <Nepomuk2/Resource>
#include <Nepomuk2/ResourceManager>
#include <Nepomuk2/Vocabulary/NIE>
#include <Nepomuk2/Vocabulary/NCO>
#include <Nepomuk2/Vocabulary/NDO>
#endif
ResourceWidget::ResourceWidget(const QString & folder, QWidget * parent) :
QDialog(parent),
m_folder(folder),
......@@ -111,9 +91,6 @@ ResourceWidget::ResourceWidget(const QString & folder, QWidget * parent) :
sound_box->setEnabled(false);
search_text->setFocus();
#ifdef USE_NEPOMUK
Nepomuk::ResourceManager::instance()->init();
#endif
slotChangeService();
loadConfig();
}
......@@ -279,26 +256,6 @@ void ResourceWidget::slotGotFile(KJob *job)
if (job->error() != 0 ) return;
KIO::FileCopyJob* copyJob = static_cast<KIO::FileCopyJob*>( job );
const QUrl filePath = copyJob->destUrl();
#ifdef USE_NEPOMUK
Nepomuk::Resource res( filePath );
res.setProperty( Nepomuk::Vocabulary::NIE::license(), (Nepomuk::Variant) job->property("license") );
res.setProperty( Nepomuk::Vocabulary::NIE::licenseType(), (Nepomuk::Variant) job->property("licenseurl") );
res.setProperty( Nepomuk::Vocabulary::NDO::copiedFrom(), (Nepomuk::Variant) job->property("originurl") );
res.setProperty( Nepomuk::Vocabulary::NCO::creator(), (Nepomuk::Variant) job->property("author") );
//res.setDescription(item_description->toPlainText());
//res.setProperty( Soprano::Vocabulary::NAO::description(),
#endif
#ifdef USE_NEPOMUKCORE
Nepomuk2::Resource res( filePath );
res.setProperty( Nepomuk2::Vocabulary::NIE::license(), (Nepomuk2::Variant) job->property("license") );
res.setProperty( Nepomuk2::Vocabulary::NIE::licenseType(), (Nepomuk2::Variant) job->property("licenseurl") );
res.setProperty( Nepomuk2::Vocabulary::NDO::copiedFrom(), (Nepomuk2::Variant) job->property("originurl") );
res.setProperty( Nepomuk2::Vocabulary::NCO::creator(), (Nepomuk2::Variant) job->property("author") );
//res.setDescription(item_description->toPlainText());
//res.setProperty( Soprano::Vocabulary::NAO::description(),
#endif
emit addClip(filePath, stringMap());
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment