Changed: Initial footwork on OVQT-based mission compiler plugin.
This commit is contained in:
parent
f22c066863
commit
08f911759a
7 changed files with 573 additions and 0 deletions
code/nel/tools/3d/object_viewer_qt/src/plugins
|
@ -7,3 +7,4 @@ ADD_SUBDIRECTORY(disp_sheet_id)
|
|||
ADD_SUBDIRECTORY(object_viewer)
|
||||
ADD_SUBDIRECTORY(zone_painter)
|
||||
ADD_SUBDIRECTORY(georges_editor)
|
||||
ADD_SUBDIRECTORY(mission_compiler)
|
|
@ -0,0 +1,41 @@
|
|||
INCLUDE_DIRECTORIES( ${CMAKE_CURRENT_BINARY_DIR}
|
||||
${CMAKE_CURRENT_SOURCE_DIR}
|
||||
${LIBXML2_INCLUDE_DIR}
|
||||
${QT_INCLUDES})
|
||||
|
||||
FILE(GLOB SRC *.cpp *.h)
|
||||
|
||||
SET(OVQT_EXT_SYS_SRC ${CMAKE_CURRENT_SOURCE_DIR}/../../extension_system/iplugin.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/../../extension_system/iplugin_manager.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/../../extension_system/iplugin_spec.h)
|
||||
|
||||
SET(OVQT_PLUG_MISSION_COMPILER_HDR mission_compiler_plugin.h
|
||||
mission_compiler_main_window.h)
|
||||
|
||||
SET(OVQT_PLUG_MISSION_COMPILER_UIS mission_compiler_main_window.ui)
|
||||
|
||||
#SET(OVQT_PLUG_ZONE_PAINTER_RCS zone_painter.qrc)
|
||||
|
||||
SET(QT_USE_QTGUI TRUE)
|
||||
|
||||
QT4_WRAP_CPP(OVQT_PLUG_MISSION_COMPILER_MOC_SRC ${OVQT_PLUG_MISSION_COMPILER_HDR})
|
||||
#QT4_ADD_RESOURCES( OVQT_PLUG_ZONE_PAINTER_RC_SRCS ${OVQT_PLUG_ZONE_PAINTER_RCS})
|
||||
QT4_WRAP_UI(OVQT_PLUG_MISSION_COMPILER_UI_HDRS ${OVQT_PLUG_MISSION_COMPILER_UIS})
|
||||
|
||||
SOURCE_GROUP(QtResources FILES ${OVQT_PLUG_MISSION_COMPILER_UIS})
|
||||
SOURCE_GROUP(QtGeneratedUiHdr FILES ${OVQT_PLUG_MISSION_COMPILER_UI_HDRS})
|
||||
SOURCE_GROUP(QtGeneratedMocSrc FILES ${OVQT_PLUG_MISSION_COMPILER_MOC_SRC} )
|
||||
SOURCE_GROUP("Mission Compiler Plugin" FILES ${SRC})
|
||||
SOURCE_GROUP("OVQT Extension System" FILES ${OVQT_EXT_SYS_SRC})
|
||||
|
||||
ADD_LIBRARY(ovqt_plugin_mission_compiler MODULE ${SRC} ${OVQT_PLUG_MISSION_COMPILER_MOC_SRC} ${OVQT_EXT_SYS_SRC} ${OVQT_PLUG_MISSION_COMPILER_UI_HDRS})
|
||||
|
||||
TARGET_LINK_LIBRARIES(ovqt_plugin_mission_compiler ovqt_plugin_core nelmisc nelligo ${QT_LIBRARIES} ${QT_QTOPENGL_LIBRARY})
|
||||
|
||||
NL_DEFAULT_PROPS(ovqt_plugin_mission_compiler "NeL, Tools, 3D: Object Viewer Qt Plugin: Mission Compiler")
|
||||
NL_ADD_RUNTIME_FLAGS(ovqt_plugin_mission_compiler)
|
||||
NL_ADD_LIB_SUFFIX(ovqt_plugin_mission_compiler)
|
||||
|
||||
ADD_DEFINITIONS(${LIBXML2_DEFINITIONS} -DQT_PLUGIN -DQT_SHARED ${QT_DEFINITIONS})
|
||||
|
||||
INSTALL(TARGETS ovqt_plugin_mission_compiler LIBRARY DESTINATION lib RUNTIME DESTINATION bin ARCHIVE DESTINATION lib COMPONENT tools3d)
|
|
@ -0,0 +1,63 @@
|
|||
#include "mission_compiler_main_window.h"
|
||||
#include "ui_mission_compiler_main_window.h"
|
||||
|
||||
#include <QMenu>
|
||||
#include <QSignalMapper>
|
||||
#include <QColor>
|
||||
#include <QColorDialog>
|
||||
#include <QSettings>
|
||||
|
||||
#include "../core/icore.h"
|
||||
#include "../core/imenu_manager.h"
|
||||
#include "../core/core_constants.h"
|
||||
|
||||
#include <nel/misc/path.h>
|
||||
|
||||
MissionCompilerMainWindow::MissionCompilerMainWindow(QWidget *parent) :
|
||||
QMainWindow(parent),
|
||||
ui(new Ui::MissionCompilerMainWindow)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
|
||||
// Load the settings.
|
||||
loadConfig();
|
||||
|
||||
m_undoStack = new QUndoStack(this);
|
||||
|
||||
// Populate the "all" primitives box.
|
||||
std::vector<std::string> paths;
|
||||
NLMISC::CPath::getFileList("primitive", paths);
|
||||
|
||||
std::vector<std::string>::iterator itr = paths.begin();
|
||||
while( itr != paths.end() )
|
||||
{
|
||||
const char *path2 = (*itr).c_str();
|
||||
ui->allPrimitivesList->insertItem(0,path2);
|
||||
++itr;
|
||||
}
|
||||
}
|
||||
|
||||
void MissionCompilerMainWindow::loadConfig() {
|
||||
QSettings *settings = Core::ICore::instance()->settings();
|
||||
settings->beginGroup("MissionCompiler");
|
||||
|
||||
//QColor color;
|
||||
//color = settings->value("BackgroundColor", QColor(80, 80, 80)).value<QColor>();
|
||||
//m_nelWidget->setBackgroundColor(NLMISC::CRGBA(color.red(), color.green(), color.blue(), color.alpha()));
|
||||
}
|
||||
|
||||
void MissionCompilerMainWindow::saveConfig() {
|
||||
QSettings *settings = Core::ICore::instance()->settings();
|
||||
settings->beginGroup("MissionCompiler" );
|
||||
|
||||
//QColor color(m_nelWidget->backgroundColor().R, m_nelWidget->backgroundColor().G, m_nelWidget->backgroundColor().B, m_nelWidget->backgroundColor().A);
|
||||
//settings->setValue("BackgroundColor", color);
|
||||
|
||||
settings->endGroup();
|
||||
settings->sync();
|
||||
}
|
||||
|
||||
MissionCompilerMainWindow::~MissionCompilerMainWindow()
|
||||
{
|
||||
delete ui;
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
#ifndef MISSION_COMPILER_MAIN_WINDOW_H
|
||||
#define MISSION_COMPILER_MAIN_WINDOW_H
|
||||
|
||||
#include <QMainWindow>
|
||||
#include <QTimer>
|
||||
#include <QLabel>
|
||||
#include <QAction>
|
||||
#include <QtGui/QUndoStack>
|
||||
#include <QStringListModel>
|
||||
|
||||
namespace Ui {
|
||||
class MissionCompilerMainWindow;
|
||||
}
|
||||
|
||||
class MissionCompilerMainWindow : public QMainWindow
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit MissionCompilerMainWindow(QWidget *parent = 0);
|
||||
~MissionCompilerMainWindow();
|
||||
|
||||
void loadConfig();
|
||||
void saveConfig();
|
||||
QUndoStack *getUndoStack() { return m_undoStack; }
|
||||
|
||||
|
||||
private:
|
||||
Ui::MissionCompilerMainWindow *ui;
|
||||
|
||||
QMenu *_toolModeMenu;
|
||||
QUndoStack *m_undoStack;
|
||||
QStringListModel *m_allPrimitivesModel;
|
||||
};
|
||||
|
||||
#endif // MISSION_COMPILER_MAIN_WINDOW_H
|
|
@ -0,0 +1,195 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>MissionCompilerMainWindow</class>
|
||||
<widget class="QMainWindow" name="MissionCompilerMainWindow">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>794</width>
|
||||
<height>600</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>MainWindow</string>
|
||||
</property>
|
||||
<widget class="QWidget" name="centralwidget">
|
||||
<layout class="QGridLayout" name="gridLayout_3">
|
||||
<item row="1" column="0">
|
||||
<widget class="QToolBox" name="toolBox">
|
||||
<property name="currentIndex">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<widget class="QWidget" name="compileOptionsPage">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>776</width>
|
||||
<height>398</height>
|
||||
</rect>
|
||||
</property>
|
||||
<attribute name="label">
|
||||
<string>Mission Compiler Options</string>
|
||||
</attribute>
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<item row="0" column="1">
|
||||
<widget class="QListWidget" name="allPrimitivesList"/>
|
||||
</item>
|
||||
<item row="0" column="2">
|
||||
<layout class="QVBoxLayout" name="addRemoveLayout">
|
||||
<item>
|
||||
<spacer name="verticalSpacer_3">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>40</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="addSelectedButton">
|
||||
<property name="text">
|
||||
<string>>></string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="addAllButton">
|
||||
<property name="text">
|
||||
<string>ALL >></string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="verticalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>40</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="removeAllButton">
|
||||
<property name="text">
|
||||
<string><< ALL</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="removeSelectedButton">
|
||||
<property name="text">
|
||||
<string><<</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="verticalSpacer_2">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>40</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="0" column="3">
|
||||
<widget class="QListWidget" name="selectedPrimitivesList"/>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QWidget" name="publishOptionsPage">
|
||||
<attribute name="label">
|
||||
<string>Publish Options</string>
|
||||
</attribute>
|
||||
<layout class="QGridLayout" name="gridLayout_4">
|
||||
<item row="0" column="0">
|
||||
<widget class="QListWidget" name="publishServersList"/>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QWidget" name="compilationOutputPage">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>776</width>
|
||||
<height>398</height>
|
||||
</rect>
|
||||
</property>
|
||||
<attribute name="label">
|
||||
<string>Compilation Output</string>
|
||||
</attribute>
|
||||
<layout class="QGridLayout" name="gridLayout_2">
|
||||
<item row="0" column="0">
|
||||
<widget class="QPlainTextEdit" name="compileOutputText">
|
||||
<property name="readOnly">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<widget class="QGroupBox" name="actionsGroupBox">
|
||||
<property name="title">
|
||||
<string>Actions</string>
|
||||
</property>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<widget class="QPushButton" name="validateButton">
|
||||
<property name="text">
|
||||
<string>Validate</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="compileButton">
|
||||
<property name="text">
|
||||
<string>Compile</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="compilePublishButton">
|
||||
<property name="text">
|
||||
<string>Compile and Publish</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QMenuBar" name="menubar">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>794</width>
|
||||
<height>21</height>
|
||||
</rect>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="QStatusBar" name="statusbar"/>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
|
@ -0,0 +1,132 @@
|
|||
// Project includes
|
||||
#include "mission_compiler_plugin.h"
|
||||
#include "../core/icore.h"
|
||||
#include "../core/core_constants.h"
|
||||
#include "../core/imenu_manager.h"
|
||||
#include "../../extension_system/iplugin_spec.h"
|
||||
|
||||
// NeL includes
|
||||
#include "nel/misc/debug.h"
|
||||
|
||||
// Qt includes
|
||||
#include <QtCore/QObject>
|
||||
#include <QtGui/QMessageBox>
|
||||
#include <QtGui/QMainWindow>
|
||||
#include <QtGui/QMenu>
|
||||
#include <QtGui/QAction>
|
||||
#include <QtGui/QMenuBar>
|
||||
|
||||
namespace Plugin
|
||||
{
|
||||
|
||||
MissionCompilerPlugin::~MissionCompilerPlugin()
|
||||
{
|
||||
Q_FOREACH(QObject *obj, _autoReleaseObjects)
|
||||
{
|
||||
_plugMan->removeObject(obj);
|
||||
}
|
||||
qDeleteAll(_autoReleaseObjects);
|
||||
_autoReleaseObjects.clear();
|
||||
}
|
||||
|
||||
bool MissionCompilerPlugin::initialize(ExtensionSystem::IPluginManager *pluginManager, QString *errorString)
|
||||
{
|
||||
Q_UNUSED(errorString);
|
||||
_plugMan = pluginManager;
|
||||
|
||||
//addAutoReleasedObject(new CZonePainterSettingsPage(this));
|
||||
addAutoReleasedObject(new CMissionCompilerContext(this));
|
||||
//addAutoReleasedObject(new CCoreListener(this));
|
||||
return true;
|
||||
}
|
||||
|
||||
void MissionCompilerPlugin::extensionsInitialized()
|
||||
{
|
||||
Core::ICore *core = Core::ICore::instance();
|
||||
QSettings *settings = Core::ICore::instance()->settings();
|
||||
Core::IMenuManager *menuManager = core->menuManager();
|
||||
//menuManager = _plugMan->getObject<Core::IMenuManager>();
|
||||
//QAction *exampleAction1 = new QAction("Zone1", this);
|
||||
//QAction *exampleAction2 = new QAction("Zone2", this);
|
||||
//QMenu *toolsMenu = menuManager->menu(Core::Constants::M_TOOLS);
|
||||
//helpMenu->insertAction(aboutQtAction, exampleAction1);
|
||||
//helpMenu->addSeparator();
|
||||
//helpMenu->addAction(exampleAction2);
|
||||
//QMenu *zoneMenu = menuManager->menuBar()->addMenu("ZoneMenu");
|
||||
//zoneMenu->insertAction(aboutQtAction, exampleAction1);
|
||||
//zoneMenu->addSeparator();
|
||||
//zoneMenu->addAction(exampleAction2);
|
||||
|
||||
// Initialize Ligo.
|
||||
settings->beginGroup(Core::Constants::DATA_PATH_SECTION);
|
||||
QString ligoConfigFile = settings->value(Core::Constants::DATA_PATH_SECTION).toString();
|
||||
settings->beginGroup(Core::Constants::DATA_PATH_SECTION);
|
||||
|
||||
NLLIGO::Register();
|
||||
LigoConfig.readPrimitiveClass(ligoConfigFile.toAscii().data(), false);
|
||||
NLLIGO::CPrimitiveContext::instance().CurrentLigoConfig = &LigoConfig;
|
||||
}
|
||||
|
||||
void MissionCompilerPlugin::setNelContext(NLMISC::INelContext *nelContext)
|
||||
{
|
||||
#ifdef NL_OS_WINDOWS
|
||||
// Ensure that a context doesn't exist yet.
|
||||
// This only applies to platforms without PIC, e.g. Windows.
|
||||
nlassert(!NLMISC::INelContext::isContextInitialised());
|
||||
#endif // NL_OS_WINDOWS
|
||||
_LibContext = new NLMISC::CLibraryContext(*nelContext);
|
||||
}
|
||||
|
||||
QString MissionCompilerPlugin::name() const
|
||||
{
|
||||
return "MissionCompilerPlugin";
|
||||
}
|
||||
|
||||
QString MissionCompilerPlugin::version() const
|
||||
{
|
||||
return "0.1";
|
||||
}
|
||||
|
||||
QString MissionCompilerPlugin::vendor() const
|
||||
{
|
||||
return "Ryzom Core";
|
||||
}
|
||||
|
||||
QString MissionCompilerPlugin::description() const
|
||||
{
|
||||
return "Mission Compiler Plugin";
|
||||
}
|
||||
|
||||
QStringList MissionCompilerPlugin::dependencies() const
|
||||
{
|
||||
QStringList list;
|
||||
list.append(Core::Constants::OVQT_CORE_PLUGIN);
|
||||
//list.append("ObjectViewer");
|
||||
return list;
|
||||
}
|
||||
|
||||
void MissionCompilerPlugin::addAutoReleasedObject(QObject *obj)
|
||||
{
|
||||
_plugMan->addObject(obj);
|
||||
_autoReleaseObjects.prepend(obj);
|
||||
}
|
||||
|
||||
QObject* MissionCompilerPlugin::objectByName(const QString &name) const
|
||||
{
|
||||
Q_FOREACH (QObject *qobj, _plugMan->allObjects())
|
||||
if (qobj->objectName() == name)
|
||||
return qobj;
|
||||
return 0;
|
||||
}
|
||||
|
||||
ExtensionSystem::IPluginSpec *MissionCompilerPlugin::pluginByName(const QString &name) const
|
||||
{
|
||||
Q_FOREACH (ExtensionSystem::IPluginSpec *spec, _plugMan->plugins())
|
||||
if (spec->name() == name)
|
||||
return spec;
|
||||
return 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Q_EXPORT_PLUGIN(Plugin::MissionCompilerPlugin)
|
|
@ -0,0 +1,105 @@
|
|||
#ifndef MISSION_COMPILER_PLUGIN_H
|
||||
#define MISSION_COMPILER_PLUGIN_H
|
||||
|
||||
// Project includes
|
||||
#include "../../extension_system/iplugin.h"
|
||||
#include "../core/icontext.h"
|
||||
#include "mission_compiler_main_window.h"
|
||||
|
||||
// NeL includes
|
||||
#include <nel/misc/app_context.h>
|
||||
#include <nel/misc/singleton.h>
|
||||
#include <nel/ligo/primitive.h>
|
||||
#include <nel/ligo/ligo_config.h>
|
||||
|
||||
// Qt includes
|
||||
#include <QtCore/QObject>
|
||||
#include <QtGui/QIcon>
|
||||
|
||||
namespace NLMISC
|
||||
{
|
||||
class CLibraryContext;
|
||||
}
|
||||
|
||||
namespace ExtensionSystem
|
||||
{
|
||||
class IPluginSpec;
|
||||
}
|
||||
|
||||
namespace Plugin
|
||||
{
|
||||
|
||||
class MissionCompilerPlugin : public QObject, public ExtensionSystem::IPlugin
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_INTERFACES(ExtensionSystem::IPlugin)
|
||||
public:
|
||||
|
||||
virtual ~MissionCompilerPlugin();
|
||||
|
||||
bool initialize(ExtensionSystem::IPluginManager *pluginManager, QString *errorString);
|
||||
void extensionsInitialized();
|
||||
|
||||
void setNelContext(NLMISC::INelContext *nelContext);
|
||||
|
||||
QString name() const;
|
||||
QString version() const;
|
||||
QString vendor() const;
|
||||
QString description() const;
|
||||
QStringList dependencies() const;
|
||||
|
||||
void addAutoReleasedObject(QObject *obj);
|
||||
|
||||
QObject *objectByName(const QString &name) const;
|
||||
ExtensionSystem::IPluginSpec *pluginByName(const QString &name) const;
|
||||
|
||||
NLLIGO::CLigoConfig LigoConfig;
|
||||
|
||||
protected:
|
||||
NLMISC::CLibraryContext *_LibContext;
|
||||
|
||||
private:
|
||||
ExtensionSystem::IPluginManager *_plugMan;
|
||||
QList<QObject *> _autoReleaseObjects;
|
||||
};
|
||||
|
||||
class CMissionCompilerContext: public Core::IContext
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
CMissionCompilerContext(QObject *parent = 0): IContext(parent)
|
||||
{
|
||||
m_missionCompilerMainWindow = new MissionCompilerMainWindow();
|
||||
}
|
||||
virtual ~CMissionCompilerContext() {}
|
||||
|
||||
virtual QString id() const
|
||||
{
|
||||
return QLatin1String("MissionCompilerContext");
|
||||
}
|
||||
virtual QString trName() const
|
||||
{
|
||||
return tr("Mission Compiler");
|
||||
}
|
||||
virtual QIcon icon() const
|
||||
{
|
||||
return QIcon();
|
||||
}
|
||||
virtual QWidget *widget()
|
||||
{
|
||||
return m_missionCompilerMainWindow;
|
||||
}
|
||||
|
||||
virtual QUndoStack *undoStack()
|
||||
{
|
||||
return m_missionCompilerMainWindow->getUndoStack();
|
||||
}
|
||||
virtual void open() {}
|
||||
|
||||
|
||||
MissionCompilerMainWindow *m_missionCompilerMainWindow;
|
||||
};
|
||||
|
||||
} // namespace Plugin
|
||||
|
||||
#endif // MISSION_COMPILER_PLUGIN_H
|
Loading…
Reference in a new issue