macOS fixes

This commit is contained in:
Jack Andersen 2018-08-27 17:48:53 -10:00
parent 33d2cc9ef1
commit 4fc5dfdc76
9 changed files with 591 additions and 428 deletions

View File

@ -18,6 +18,13 @@ signals:
QMessageBox::StandardButton information(const QString &title, QMessageBox::StandardButton information(const QString &title,
const QString &text, QMessageBox::StandardButtons buttons = QMessageBox::Ok, const QString &text, QMessageBox::StandardButtons buttons = QMessageBox::Ok,
QMessageBox::StandardButton defaultButton = QMessageBox::NoButton); QMessageBox::StandardButton defaultButton = QMessageBox::NoButton);
int question(const QString &title,
const QString& text,
const QString& button0Text,
const QString& button1Text = QString(),
const QString& button2Text = QString(),
int defaultButtonNumber = 0,
int escapeButtonNumber = -1);
QMessageBox::StandardButton question(const QString &title, QMessageBox::StandardButton question(const QString &title,
const QString &text, QMessageBox::StandardButtons buttons = const QString &text, QMessageBox::StandardButtons buttons =
QMessageBox::StandardButtons(QMessageBox::Yes | QMessageBox::No), QMessageBox::StandardButtons(QMessageBox::Yes | QMessageBox::No),

View File

@ -189,6 +189,20 @@ void MainWindow::connectMessenger(UIMessenger* messenger, Qt::ConnectionType typ
this, SLOT(msgInformation(const QString&, this, SLOT(msgInformation(const QString&,
const QString&, QMessageBox::StandardButtons, const QString&, QMessageBox::StandardButtons,
QMessageBox::StandardButton)), type); QMessageBox::StandardButton)), type);
connect(messenger, SIGNAL(question(const QString&,
const QString&,
const QString&,
const QString&,
const QString&,
int,
int)),
this, SLOT(msgQuestion(const QString&,
const QString&,
const QString&,
const QString&,
const QString&,
int,
int)), type);
connect(messenger, SIGNAL(question(const QString&, connect(messenger, SIGNAL(question(const QString&,
const QString&, QMessageBox::StandardButtons, const QString&, QMessageBox::StandardButtons,
QMessageBox::StandardButton)), QMessageBox::StandardButton)),
@ -256,13 +270,13 @@ bool MainWindow::setProjectPath(const QString& path)
if (dir.path().isEmpty() || dir.path() == QStringLiteral(".") || dir.path() == QStringLiteral("..")) if (dir.path().isEmpty() || dir.path() == QStringLiteral(".") || dir.path() == QStringLiteral(".."))
{ {
QString msg = QString(tr("The directory at '%1' must not be empty.")).arg(path); QString msg = QString(tr("The directory at '%1' must not be empty.")).arg(path);
QMessageBox::critical(this, tr("Directory empty"), msg); m_mainMessenger.critical(tr("Directory empty"), msg);
return false; return false;
} }
else if (!dir.exists()) else if (!dir.exists())
{ {
QString msg = QString(tr("The directory at '%1' must exist for the Amuse editor.")).arg(path); QString msg = QString(tr("The directory at '%1' must exist for the Amuse editor.")).arg(path);
QMessageBox::critical(this, tr("Directory does not exist"), msg); m_mainMessenger.critical(tr("Directory does not exist"), msg);
return false; return false;
} }
QString testWritePath = dir.filePath(tr("__amuse_test__")); QString testWritePath = dir.filePath(tr("__amuse_test__"));
@ -272,7 +286,7 @@ bool MainWindow::setProjectPath(const QString& path)
QString msg = QString(tr("The directory at '%1' must be writable for the Amuse editor: %2")).arg(path). QString msg = QString(tr("The directory at '%1' must be writable for the Amuse editor: %2")).arg(path).
arg(testWriteFile.errorString()); arg(testWriteFile.errorString());
QMessageBox::critical(this, tr("Unable to write to directory"), msg); m_mainMessenger.critical(tr("Unable to write to directory"), msg);
return false; return false;
} }
testWriteFile.remove(); testWriteFile.remove();
@ -385,10 +399,13 @@ void MainWindow::timerEvent(QTimerEvent* ev)
if (m_voxEngine && m_engine) if (m_voxEngine && m_engine)
{ {
m_voxEngine->pumpAndMixVoices(); m_voxEngine->pumpAndMixVoices();
m_ui.statusbar->setVoiceCount(int(m_engine->getNumTotalActiveVoices())); if (!(m_timerFireCount % 10)) /* Rate limit voice counter */
m_ui.statusbar->setVoiceCount(int(m_engine->getNumTotalActiveVoices()));
if (m_engine->getActiveVoices().empty() && m_uiDisabled) if (m_engine->getActiveVoices().empty() && m_uiDisabled)
{ {
m_ui.projectOutline->setEnabled(true); m_ui.projectOutline->setEnabled(true);
m_ui.backButton->setEnabled(true);
m_ui.forwardButton->setEnabled(true);
if (EditorWidget* w = getEditorWidget()) if (EditorWidget* w = getEditorWidget())
w->setEditorEnabled(true); w->setEditorEnabled(true);
m_ui.menubar->setEnabled(true); m_ui.menubar->setEnabled(true);
@ -397,6 +414,8 @@ void MainWindow::timerEvent(QTimerEvent* ev)
else if (!m_engine->getActiveVoices().empty() && !m_uiDisabled) else if (!m_engine->getActiveVoices().empty() && !m_uiDisabled)
{ {
m_ui.projectOutline->setEnabled(false); m_ui.projectOutline->setEnabled(false);
m_ui.backButton->setEnabled(false);
m_ui.forwardButton->setEnabled(false);
if (EditorWidget* w = getEditorWidget()) if (EditorWidget* w = getEditorWidget())
w->setEditorEnabled(false); w->setEditorEnabled(false);
m_ui.menubar->setEnabled(false); m_ui.menubar->setEnabled(false);
@ -425,6 +444,8 @@ void MainWindow::timerEvent(QTimerEvent* ev)
sfxTable->indexWidget(sfxTable->model()->index(i, 1)))) sfxTable->indexWidget(sfxTable->model()->index(i, 1))))
if (player->voice() && player->voice()->state() != amuse::VoiceState::Playing) if (player->voice() && player->voice()->state() != amuse::VoiceState::Playing)
player->stopped(); player->stopped();
++m_timerFireCount;
} }
} }
@ -740,7 +761,7 @@ void MainWindow::closeEvent(QCloseEvent* ev)
if (!m_undoStack->isClean()) if (!m_undoStack->isClean())
{ {
QDir dir(m_projectModel->path()); QDir dir(m_projectModel->path());
int result = QMessageBox::question(this, tr("Unsaved Changes"), tr("Save Changes in %1?").arg(dir.dirName()), int result = m_mainMessenger.question(tr("Unsaved Changes"), tr("Save Changes in %1?").arg(dir.dirName()),
QMessageBox::Save | QMessageBox::Discard | QMessageBox::Cancel, QMessageBox::Save); QMessageBox::Save | QMessageBox::Discard | QMessageBox::Cancel, QMessageBox::Save);
if (result == QMessageBox::Save) if (result == QMessageBox::Save)
{ {
@ -789,13 +810,13 @@ bool MainWindow::openProject(const QString& path)
if (dir.path().isEmpty() || dir.path() == QStringLiteral(".") || dir.path() == QStringLiteral("..")) if (dir.path().isEmpty() || dir.path() == QStringLiteral(".") || dir.path() == QStringLiteral(".."))
{ {
QString msg = QString(tr("The directory at '%1' must not be empty.")).arg(path); QString msg = QString(tr("The directory at '%1' must not be empty.")).arg(path);
QMessageBox::critical(this, tr("Directory empty"), msg); m_mainMessenger.critical(tr("Directory empty"), msg);
return false; return false;
} }
else if (!dir.exists()) else if (!dir.exists())
{ {
QString msg = QString(tr("The directory at '%1' does not exist.")).arg(path); QString msg = QString(tr("The directory at '%1' does not exist.")).arg(path);
QMessageBox::critical(this, tr("Bad Directory"), msg); m_mainMessenger.critical(tr("Bad Directory"), msg);
return false; return false;
} }
@ -935,12 +956,12 @@ void MainWindow::importAction()
if (tp == amuse::ContainerRegistry::Type::Invalid) if (tp == amuse::ContainerRegistry::Type::Invalid)
{ {
QString msg = QString(tr("The file at '%1' could not be interpreted as a MusyX container.")).arg(path); QString msg = QString(tr("The file at '%1' could not be interpreted as a MusyX container.")).arg(path);
QMessageBox::critical(this, tr("Unsupported MusyX Container"), msg); m_mainMessenger.critical(tr("Unsupported MusyX Container"), msg);
return; return;
} }
/* Ask user about sample conversion */ /* Ask user about sample conversion */
int impMode = QMessageBox::question(this, tr("Sample Import Mode"), int impMode = m_mainMessenger.question(tr("Sample Import Mode"),
tr("Amuse can import samples as WAV files for ease of editing, " tr("Amuse can import samples as WAV files for ease of editing, "
"import original compressed data for lossless repacking, or both. " "import original compressed data for lossless repacking, or both. "
"Exporting the project will prefer whichever version was modified " "Exporting the project will prefer whichever version was modified "
@ -961,9 +982,9 @@ void MainWindow::importAction()
/* Special handling for raw groups - gather sibling groups in filesystem */ /* Special handling for raw groups - gather sibling groups in filesystem */
if (tp == amuse::ContainerRegistry::Type::Raw4) if (tp == amuse::ContainerRegistry::Type::Raw4)
{ {
int scanMode = QMessageBox::question(this, tr("Raw Import Mode"), int scanMode = m_mainMessenger.question(tr("Raw Import Mode"),
tr("Would you like to scan for all MusyX group files in this directory?"), tr("Would you like to scan for all MusyX group files in this directory?"),
QMessageBox::Yes, QMessageBox::No); QMessageBox::Yes | QMessageBox::No, QMessageBox::No);
if (scanMode == QMessageBox::Yes) if (scanMode == QMessageBox::Yes)
{ {
/* Auto-create project */ /* Auto-create project */
@ -1616,9 +1637,9 @@ void MainWindow::aboutAmuseAction()
oldMsgBox = msgBox; oldMsgBox = msgBox;
#if 0 #if 0
// ### doesn't work until close button is enabled in title bar // ### doesn't work until close button is enabled in title bar
msgBox->d_func()->autoAddOkButton = false; //msgBox->d_func()->autoAddOkButton = false;
#else #else
msgBox->d_func()->buttonBox->setCenterButtons(true); //msgBox->d_func()->buttonBox->setCenterButtons(true);
#endif #endif
msgBox->show(); msgBox->show();
#else #else
@ -1903,13 +1924,14 @@ void MainWindow::onBackgroundTaskFinished(int id)
if (m_mainMessenger.question(tr("Export Complete"), tr("%1?"). if (m_mainMessenger.question(tr("Export Complete"), tr("%1?").
arg(ShowInGraphicalShellString())) == QMessageBox::Yes) arg(ShowInGraphicalShellString())) == QMessageBox::Yes)
{ {
QFileInfo dirInfo(m_projectModel->dir(), QStringLiteral("out")); QFileInfo
dirInfo(m_projectModel->dir(), QStringLiteral("out"));
QDir dir(dirInfo.filePath()); QDir dir(dirInfo.filePath());
QStringList entryList = dir.entryList(QDir::Files); QStringList entryList = dir.entryList(QDir::Files);
ShowInGraphicalShell(this, entryList.empty() ? dirInfo.filePath() : QFileInfo(dir, entryList.first()).filePath()); ShowInGraphicalShell(this,
entryList.empty() ? dirInfo.filePath() : QFileInfo(dir, entryList.first()).filePath());
} }
} } else
else
{ {
bool hasGroups = m_projectModel->ensureModelData(); bool hasGroups = m_projectModel->ensureModelData();
m_ui.actionImport_Groups->setDisabled(hasGroups); m_ui.actionImport_Groups->setDisabled(hasGroups);
@ -1919,30 +1941,97 @@ void MainWindow::onBackgroundTaskFinished(int id)
setEnabled(true); setEnabled(true);
} }
static int ShowOldMessageBox(QWidget *parent, QMessageBox::Icon icon,
const QString &title, const QString &text,
const QString &button0Text,
const QString &button1Text,
const QString &button2Text,
int defaultButtonNumber,
int escapeButtonNumber)
{
QMessageBox messageBox(icon, title, text, QMessageBox::NoButton, parent);
messageBox.setWindowModality(Qt::WindowModal);
QString myButton0Text = button0Text;
if (myButton0Text.isEmpty())
myButton0Text = QDialogButtonBox::tr("OK");
messageBox.addButton(myButton0Text, QMessageBox::ActionRole);
if (!button1Text.isEmpty())
messageBox.addButton(button1Text, QMessageBox::ActionRole);
if (!button2Text.isEmpty())
messageBox.addButton(button2Text, QMessageBox::ActionRole);
const QList<QAbstractButton *> &buttonList = messageBox.buttons();
messageBox.setDefaultButton(static_cast<QPushButton *>(buttonList.value(defaultButtonNumber)));
messageBox.setEscapeButton(buttonList.value(escapeButtonNumber));
return messageBox.exec();
}
static QMessageBox::StandardButton ShowNewMessageBox(QWidget *parent,
QMessageBox::Icon icon, const QString& title, const QString& text,
QMessageBox::StandardButtons buttons, QMessageBox::StandardButton defaultButton)
{
QMessageBox msgBox(icon, title, text, QMessageBox::NoButton, parent);
msgBox.setWindowModality(Qt::WindowModal);
QDialogButtonBox *buttonBox = msgBox.findChild<QDialogButtonBox*>();
Q_ASSERT(buttonBox != 0);
uint mask = QMessageBox::FirstButton;
while (mask <= QMessageBox::LastButton) {
uint sb = buttons & mask;
mask <<= 1;
if (!sb)
continue;
QPushButton *button = msgBox.addButton((QMessageBox::StandardButton)sb);
// Choose the first accept role as the default
if (msgBox.defaultButton())
continue;
if ((defaultButton == QMessageBox::NoButton && buttonBox->buttonRole(button) == QDialogButtonBox::AcceptRole)
|| (defaultButton != QMessageBox::NoButton && sb == uint(defaultButton)))
msgBox.setDefaultButton(button);
}
if (msgBox.exec() == -1)
return QMessageBox::Cancel;
return msgBox.standardButton(msgBox.clickedButton());
}
QMessageBox::StandardButton MainWindow::msgInformation(const QString &title, QMessageBox::StandardButton MainWindow::msgInformation(const QString &title,
const QString &text, QMessageBox::StandardButtons buttons, const QString &text, QMessageBox::StandardButtons buttons,
QMessageBox::StandardButton defaultButton) QMessageBox::StandardButton defaultButton)
{ {
return QMessageBox::information(this, title, text, buttons, defaultButton); return ShowNewMessageBox(this, QMessageBox::Information, title, text, buttons, defaultButton);
}
int MainWindow::msgQuestion(const QString &title,
const QString& text,
const QString& button0Text,
const QString& button1Text,
const QString& button2Text,
int defaultButtonNumber,
int escapeButtonNumber)
{
return ShowOldMessageBox(this, QMessageBox::Question, title, text,
button0Text, button1Text, button2Text,
defaultButtonNumber, escapeButtonNumber);
} }
QMessageBox::StandardButton MainWindow::msgQuestion(const QString &title, QMessageBox::StandardButton MainWindow::msgQuestion(const QString &title,
const QString &text, QMessageBox::StandardButtons buttons, const QString &text, QMessageBox::StandardButtons buttons,
QMessageBox::StandardButton defaultButton) QMessageBox::StandardButton defaultButton)
{ {
return QMessageBox::question(this, title, text, buttons, defaultButton); return ShowNewMessageBox(this, QMessageBox::Question, title, text, buttons, defaultButton);
} }
QMessageBox::StandardButton MainWindow::msgWarning(const QString &title, QMessageBox::StandardButton MainWindow::msgWarning(const QString &title,
const QString &text, QMessageBox::StandardButtons buttons, const QString &text, QMessageBox::StandardButtons buttons,
QMessageBox::StandardButton defaultButton) QMessageBox::StandardButton defaultButton)
{ {
return QMessageBox::warning(this, title, text, buttons, defaultButton); return ShowNewMessageBox(this, QMessageBox::Warning, title, text, buttons, defaultButton);
} }
QMessageBox::StandardButton MainWindow::msgCritical(const QString &title, QMessageBox::StandardButton MainWindow::msgCritical(const QString &title,
const QString &text, QMessageBox::StandardButtons buttons, const QString &text, QMessageBox::StandardButtons buttons,
QMessageBox::StandardButton defaultButton) QMessageBox::StandardButton defaultButton)
{ {
return QMessageBox::critical(this, title, text, buttons, defaultButton); return ShowNewMessageBox(this, QMessageBox::Critical, title, text, buttons, defaultButton);
} }

View File

@ -142,6 +142,8 @@ class MainWindow : public QMainWindow
QProgressDialog* m_backgroundDialog = nullptr; QProgressDialog* m_backgroundDialog = nullptr;
QThread m_backgroundThread; QThread m_backgroundThread;
uint64_t m_timerFireCount = 0;
void connectMessenger(UIMessenger* messenger, Qt::ConnectionType type); void connectMessenger(UIMessenger* messenger, Qt::ConnectionType type);
void updateWindowTitle(); void updateWindowTitle();
@ -271,6 +273,13 @@ public slots:
QMessageBox::StandardButton msgInformation(const QString &title, QMessageBox::StandardButton msgInformation(const QString &title,
const QString &text, QMessageBox::StandardButtons buttons = QMessageBox::Ok, const QString &text, QMessageBox::StandardButtons buttons = QMessageBox::Ok,
QMessageBox::StandardButton defaultButton = QMessageBox::NoButton); QMessageBox::StandardButton defaultButton = QMessageBox::NoButton);
int msgQuestion(const QString &title,
const QString& text,
const QString& button0Text,
const QString& button1Text = QString(),
const QString& button2Text = QString(),
int defaultButtonNumber = 0,
int escapeButtonNumber = -1);
QMessageBox::StandardButton msgQuestion(const QString &title, QMessageBox::StandardButton msgQuestion(const QString &title,
const QString &text, QMessageBox::StandardButtons buttons = const QString &text, QMessageBox::StandardButtons buttons =
QMessageBox::StandardButtons(QMessageBox::Yes | QMessageBox::No), QMessageBox::StandardButtons(QMessageBox::Yes | QMessageBox::No),

View File

@ -24,10 +24,18 @@ public:
{ {
case 0: case 0:
{ {
if (m_prog == m_undoVal)
break;
#if __APPLE__
auto search = map.find(m_prog);
std::swap(map[m_undoVal], search->second);
map.erase(search);
#else
auto nh = map.extract(m_prog); auto nh = map.extract(m_prog);
nh.key() = m_undoVal; nh.key() = m_undoVal;
m_prog = m_undoVal;
map.insert(std::move(nh)); map.insert(std::move(nh));
#endif
m_prog = m_undoVal;
break; break;
} }
case 1: case 1:
@ -55,11 +63,19 @@ public:
{ {
case 0: case 0:
{ {
auto nh = map.extract(m_prog);
m_undoVal = m_prog; m_undoVal = m_prog;
if (m_prog == m_redoVal)
break;
#if __APPLE__
auto search = map.find(m_prog);
std::swap(map[m_redoVal], search->second);
map.erase(search);
#else
auto nh = map.extract(m_prog);
nh.key() = m_redoVal; nh.key() = m_redoVal;
m_prog = m_redoVal;
map.insert(std::move(nh)); map.insert(std::move(nh));
#endif
m_prog = m_redoVal;
break; break;
} }
case 1: case 1:
@ -178,10 +194,19 @@ public:
amuse::SongId newId = g_MainWindow->projectModel()->exchangeSongId(m_song, m_undoVal); amuse::SongId newId = g_MainWindow->projectModel()->exchangeSongId(m_song, m_undoVal);
auto nh = map.extract(m_song); if (m_song != newId)
nh.key() = newId; {
m_song = newId; #if __APPLE__
map.insert(std::move(nh)); auto search = map.find(m_song);
std::swap(map[newId], search->second);
map.erase(search);
#else
auto nh = map.extract(m_song);
nh.key() = newId;
map.insert(std::move(nh));
#endif
m_song = newId;
}
EditorUndoCommand::undo(); EditorUndoCommand::undo();
} }
@ -194,10 +219,19 @@ public:
m_undoVal = amuse::SongId::CurNameDB->resolveNameFromId(m_song); m_undoVal = amuse::SongId::CurNameDB->resolveNameFromId(m_song);
amuse::SongId newId = g_MainWindow->projectModel()->exchangeSongId(m_song, m_redoVal); amuse::SongId newId = g_MainWindow->projectModel()->exchangeSongId(m_song, m_redoVal);
auto nh = map.extract(m_song); if (m_song != newId)
nh.key() = newId; {
m_song = newId; #if __APPLE__
map.insert(std::move(nh)); auto search = map.find(m_song);
std::swap(map[newId], search->second);
map.erase(search);
#else
auto nh = map.extract(m_song);
nh.key() = newId;
map.insert(std::move(nh));
#endif
m_song = newId;
}
if (m_undid) if (m_undid)
EditorUndoCommand::redo(); EditorUndoCommand::redo();
@ -622,7 +656,7 @@ bool PageModel::setData(const QModelIndex& index, const QVariant& value, int rol
return false; return false;
if (map.find(prog) != map.cend()) if (map.find(prog) != map.cend())
{ {
QMessageBox::critical(g_MainWindow, tr("Program Conflict"), g_MainWindow->uiMessenger().critical(tr("Program Conflict"),
tr("Program %1 is already defined in table").arg(value.toInt())); tr("Program %1 is already defined in table").arg(value.toInt()));
return false; return false;
} }
@ -895,8 +929,8 @@ bool SetupListModel::setData(const QModelIndex& index, const QVariant& value, in
{ {
if (idIt->second == entry->first) if (idIt->second == entry->first)
return false; return false;
QMessageBox::critical(g_MainWindow, tr("Song Conflict"), g_MainWindow->uiMessenger().critical(tr("Song Conflict"),
tr("Song %1 is already defined in project").arg(value.toString())); tr("Song %1 is already defined in project").arg(value.toString()));
return false; return false;
} }
emit layoutAboutToBeChanged(); emit layoutAboutToBeChanged();

View File

@ -300,8 +300,8 @@ bool SFXModel::setData(const QModelIndex& index, const QVariant& value, int role
{ {
if (idIt->second == entry->first) if (idIt->second == entry->first)
return false; return false;
QMessageBox::critical(g_MainWindow, tr("SFX Conflict"), g_MainWindow->uiMessenger().critical(tr("SFX Conflict"),
tr("SFX %1 is already defined in project").arg(value.toString())); tr("SFX %1 is already defined in project").arg(value.toString()));
return false; return false;
} }
emit layoutAboutToBeChanged(); emit layoutAboutToBeChanged();

File diff suppressed because it is too large Load Diff

View File

@ -10,6 +10,7 @@
#include <string_view> #include <string_view>
#include <cstring> #include <cstring>
#include <atomic> #include <atomic>
#include <unordered_map>
#include "athena/DNA.hpp" #include "athena/DNA.hpp"
#ifndef _WIN32 #ifndef _WIN32

View File

@ -512,8 +512,12 @@ static void SetAudioFileTime(const SystemString& path, const Sstat& stat)
#if _WIN32 #if _WIN32
__utimbuf64 times = { stat.st_atime, stat.st_mtime }; __utimbuf64 times = { stat.st_atime, stat.st_mtime };
_wutime64(path.c_str(), &times); _wutime64(path.c_str(), &times);
#else
#if __APPLE__
struct timespec times[] = { stat.st_atimespec, stat.st_mtimespec };
#else #else
struct timespec times[] = { stat.st_atim, stat.st_mtim }; struct timespec times[] = { stat.st_atim, stat.st_mtim };
#endif
utimensat(AT_FDCWD, path.c_str(), times, 0); utimensat(AT_FDCWD, path.c_str(), times, 0);
#endif #endif
} }

View File

@ -30,7 +30,11 @@ bool Copy(const SystemChar* from, const SystemChar* to)
struct stat theStat; struct stat theStat;
if (::stat(from, &theStat)) if (::stat(from, &theStat))
return true; return true;
#if __APPLE__
struct timespec times[] = { theStat.st_atimespec, theStat.st_mtimespec };
#else
struct timespec times[] = { theStat.st_atim, theStat.st_mtim }; struct timespec times[] = { theStat.st_atim, theStat.st_mtim };
#endif
utimensat(AT_FDCWD, to, times, 0); utimensat(AT_FDCWD, to, times, 0);
return true; return true;
#endif #endif
@ -399,13 +403,20 @@ void NameDB::rename(ObjectId id, std::string_view str)
auto search = m_idToString.find(id); auto search = m_idToString.find(id);
if (search == m_idToString.cend()) if (search == m_idToString.cend())
return; return;
if (search->second == str)
return;
auto search2 = m_stringToId.find(search->second); auto search2 = m_stringToId.find(search->second);
if (search2 == m_stringToId.cend()) if (search2 == m_stringToId.cend())
return; return;
#if __APPLE__
std::swap(m_stringToId[std::string(str)], search2->second);
m_stringToId.erase(search2);
#else
auto nh = m_stringToId.extract(search2); auto nh = m_stringToId.extract(search2);
nh.key() = str; nh.key() = str;
m_stringToId.insert(std::move(nh)); m_stringToId.insert(std::move(nh));
m_idToString[id] = str; #endif
search->second = str;
} }
template<> template<>