Merge "Merge remote-tracking branch 'origin/4.5'"

This commit is contained in:
Eike Ziller
2018-01-09 12:44:32 +00:00
committed by The Qt Project
19 changed files with 85 additions and 110 deletions

View File

@@ -176,7 +176,7 @@ Timeline_RangeColor=selectedBackground
VcsBase_FileStatusUnknown_TextColor=text VcsBase_FileStatusUnknown_TextColor=text
VcsBase_FileAdded_TextColor=ff00ff00 VcsBase_FileAdded_TextColor=ff00ff00
VcsBase_FileModified_TextColor=ff8ee0ff VcsBase_FileModified_TextColor=ff8ee0ff
VcsBase_FileDeleted_TextColor=fffff6c6c VcsBase_FileDeleted_TextColor=ffff6c6c
VcsBase_FileRenamed_TextColor=ffffa500 VcsBase_FileRenamed_TextColor=ffffa500
VcsBase_FileUnmerged_TextColor=ffff4040 VcsBase_FileUnmerged_TextColor=ffff4040

View File

@@ -35841,7 +35841,7 @@ For more details, see /etc/sysctl.d/10-ptrace.conf
</message> </message>
<message> <message>
<source>No compiler can produce code for this Qt version. Please define one or more compilers for: %1</source> <source>No compiler can produce code for this Qt version. Please define one or more compilers for: %1</source>
<translation>Компилятор не может создавть код для этого профиля Qt. Задайте минимум один компилятор для: %1</translation> <translation>Компилятор не может создавать код для этого профиля Qt. Задайте минимум один компилятор для: %1</translation>
</message> </message>
<message> <message>
<source>The following ABIs are currently not supported: %1</source> <source>The following ABIs are currently not supported: %1</source>

View File

@@ -473,18 +473,13 @@ bool CompilerOptionsBuilder::excludeDefineDirective(const ProjectExplorer::Macro
bool CompilerOptionsBuilder::excludeHeaderPath(const QString &headerPath) const bool CompilerOptionsBuilder::excludeHeaderPath(const QString &headerPath) const
{ {
// A clang tool chain might have another version and passing in the // Always exclude clang system includes (including intrinsics) which do not come with libclang
// intrinsics path from that version will lead to errors (unknown // that Qt Creator uses for code model.
// intrinsics, unfavorable order with regard to include_next). // For example GCC on macOS uses system clang include path which makes clang code model
if (m_projectPart.toolchainType == ProjectExplorer::Constants::CLANG_TOOLCHAIN_TYPEID) { // include incorrect system headers.
if (headerPath.contains("lib/gcc/i686-apple-darwin")) static QRegularExpression clangIncludeDir(
return true; QLatin1String("\\A.*/lib/clang/\\d+\\.\\d+(\\.\\d+)?/include\\z"));
static QRegularExpression clangIncludeDir( return clangIncludeDir.match(headerPath).hasMatch();
QLatin1String("\\A.*/lib/clang/\\d+\\.\\d+(\\.\\d+)?/include\\z"));
return clangIncludeDir.match(headerPath).hasMatch();
}
return false;
} }
void CompilerOptionsBuilder::addPredefinedHeaderPathsOptions() void CompilerOptionsBuilder::addPredefinedHeaderPathsOptions()

View File

@@ -3949,14 +3949,22 @@ void GdbEngine::loadInitScript()
void GdbEngine::setEnvironmentVariables() void GdbEngine::setEnvironmentVariables()
{ {
auto isWindowsPath = [this](const QString &str){
return HostOsInfo::isWindowsHost()
&& !isRemoteEngine()
&& str.compare("path", Qt::CaseInsensitive) == 0;
};
Environment sysEnv = Environment::systemEnvironment(); Environment sysEnv = Environment::systemEnvironment();
Environment runEnv = runParameters().inferior.environment; Environment runEnv = runParameters().inferior.environment;
foreach (const EnvironmentItem &item, sysEnv.diff(runEnv)) { foreach (const EnvironmentItem &item, sysEnv.diff(runEnv)) {
// imitate the weird windows gdb behavior of setting the case of the path environment
// variable name to an all uppercase PATH
const QString name = isWindowsPath(item.name) ? "PATH" : item.name;
if (item.operation == EnvironmentItem::Unset) if (item.operation == EnvironmentItem::Unset)
runCommand({"unset environment " + item.name}); runCommand({"unset environment " + name});
else else
runCommand({"-gdb-set environment " + item.name + '=' runCommand({"-gdb-set environment " + name + '=' + item.value});
+ item.value});
} }
} }

View File

@@ -331,6 +331,11 @@ void GerritPlugin::push(const QString &topLevel)
GitPlugin::client()->push(topLevel, {dialog.selectedRemoteName(), dialog.pushTarget()}); GitPlugin::client()->push(topLevel, {dialog.selectedRemoteName(), dialog.pushTarget()});
} }
static QString currentRepository()
{
return GitPlugin::instance()->currentState().topLevel();
}
// Open or raise the Gerrit dialog window. // Open or raise the Gerrit dialog window.
void GerritPlugin::openView() void GerritPlugin::openView()
{ {
@@ -341,8 +346,7 @@ void GerritPlugin::openView()
if (!ICore::showOptionsDialog("Gerrit")) if (!ICore::showOptionsDialog("Gerrit"))
return; return;
} }
const QString repository = GitPlugin::instance()->currentState().topLevel(); GerritDialog *gd = new GerritDialog(m_parameters, m_server, currentRepository(), ICore::mainWindow());
GerritDialog *gd = new GerritDialog(m_parameters, m_server, repository, ICore::mainWindow());
gd->setModal(false); gd->setModal(false);
connect(gd, &GerritDialog::fetchDisplay, this, connect(gd, &GerritDialog::fetchDisplay, this,
[this](const QSharedPointer<GerritChange> &change) { fetch(change, FetchDisplay); }); [this](const QSharedPointer<GerritChange> &change) { fetch(change, FetchDisplay); });
@@ -354,6 +358,7 @@ void GerritPlugin::openView()
connect(this, &GerritPlugin::fetchFinished, gd, &GerritDialog::fetchFinished); connect(this, &GerritPlugin::fetchFinished, gd, &GerritDialog::fetchFinished);
m_dialog = gd; m_dialog = gd;
} else { } else {
m_dialog->setCurrentPath(currentRepository());
m_dialog->refresh(); m_dialog->refresh();
} }
const Qt::WindowStates state = m_dialog->windowState(); const Qt::WindowStates state = m_dialog->windowState();
@@ -365,7 +370,7 @@ void GerritPlugin::openView()
void GerritPlugin::push() void GerritPlugin::push()
{ {
push(GitPlugin::instance()->currentState().topLevel()); push(currentRepository());
} }
Utils::FileName GerritPlugin::gitBinDirectory() Utils::FileName GerritPlugin::gitBinDirectory()

View File

@@ -80,9 +80,6 @@ ExtraCompiler::ExtraCompiler(const Project *project, const Utils::FileName &sour
d->contents.insert(target, QByteArray()); d->contents.insert(target, QByteArray());
d->timer.setSingleShot(true); d->timer.setSingleShot(true);
connect(d->project, &Project::activeTargetChanged, this, &ExtraCompiler::onActiveTargetChanged);
onActiveTargetChanged();
connect(&d->timer, &QTimer::timeout, this, [this](){ connect(&d->timer, &QTimer::timeout, this, [this](){
if (d->dirty && d->lastEditor) { if (d->dirty && d->lastEditor) {
d->dirty = false; d->dirty = false;
@@ -254,41 +251,6 @@ void ExtraCompiler::onEditorAboutToClose(Core::IEditor *editor)
d->lastEditor = nullptr; d->lastEditor = nullptr;
} }
void ExtraCompiler::onActiveTargetChanged()
{
disconnect(d->activeBuildConfigConnection);
if (Target *target = d->project->activeTarget()) {
d->activeBuildConfigConnection = connect(
target, &Target::activeBuildConfigurationChanged,
this, &ExtraCompiler::onActiveBuildConfigurationChanged);
onActiveBuildConfigurationChanged();
} else {
disconnect(d->activeEnvironmentConnection);
setDirty();
}
}
void ExtraCompiler::onActiveBuildConfigurationChanged()
{
disconnect(d->activeEnvironmentConnection);
Target *target = d->project->activeTarget();
QTC_ASSERT(target, return);
if (BuildConfiguration *bc = target->activeBuildConfiguration()) {
d->activeEnvironmentConnection = connect(
bc, &BuildConfiguration::environmentChanged,
this, &ExtraCompiler::setDirty);
} else {
d->activeEnvironmentConnection = connect(KitManager::instance(), &KitManager::kitUpdated,
this, [this](Kit *kit) {
Target *target = d->project->activeTarget();
QTC_ASSERT(target, return);
if (kit == target->kit())
setDirty();
});
}
setDirty();
}
Utils::Environment ExtraCompiler::buildEnvironment() const Utils::Environment ExtraCompiler::buildEnvironment() const
{ {
if (Target *target = project()->activeTarget()) { if (Target *target = project()->activeTarget()) {

View File

@@ -84,8 +84,6 @@ private:
void onTargetsBuilt(Project *project); void onTargetsBuilt(Project *project);
void onEditorChanged(Core::IEditor *editor); void onEditorChanged(Core::IEditor *editor);
void onEditorAboutToClose(Core::IEditor *editor); void onEditorAboutToClose(Core::IEditor *editor);
void onActiveTargetChanged();
void onActiveBuildConfigurationChanged();
void setDirty(); void setDirty();
// This method may not block! // This method may not block!
virtual void run(const QByteArray &sourceContent) = 0; virtual void run(const QByteArray &sourceContent) = 0;

View File

@@ -125,7 +125,6 @@ QbsProject::QbsProject(const FileName &fileName) :
m_parsingScheduled(false), m_parsingScheduled(false),
m_cancelStatus(CancelStatusNone), m_cancelStatus(CancelStatusNone),
m_cppCodeModelUpdater(new CppTools::CppProjectUpdater(this)), m_cppCodeModelUpdater(new CppTools::CppProjectUpdater(this)),
m_currentBc(0),
m_extraCompilersPending(false) m_extraCompilersPending(false)
{ {
m_parsingDelay.setInterval(1000); // delay parsing by 1s. m_parsingDelay.setInterval(1000); // delay parsing by 1s.
@@ -146,6 +145,7 @@ QbsProject::QbsProject(const FileName &fileName) :
}; };
subscribeSignal(&BuildConfiguration::environmentChanged, this, delayedParsing); subscribeSignal(&BuildConfiguration::environmentChanged, this, delayedParsing);
subscribeSignal(&BuildConfiguration::buildDirectoryChanged, this, delayedParsing); subscribeSignal(&BuildConfiguration::buildDirectoryChanged, this, delayedParsing);
subscribeSignal(&QbsBuildConfiguration::qbsConfigurationChanged, this, delayedParsing);
subscribeSignal(&Target::activeBuildConfigurationChanged, this, delayedParsing); subscribeSignal(&Target::activeBuildConfigurationChanged, this, delayedParsing);
connect(&m_parsingDelay, &QTimer::timeout, this, &QbsProject::startParsing); connect(&m_parsingDelay, &QTimer::timeout, this, &QbsProject::startParsing);
@@ -331,11 +331,6 @@ bool QbsProject::renameFileInProduct(const QString &oldPath, const QString &newP
return addFilesToProduct(QStringList() << newPath, newProductData, newGroupData, &dummy); return addFilesToProduct(QStringList() << newPath, newProductData, newGroupData, &dummy);
} }
void QbsProject::invalidate()
{
prepareForParsing();
}
static qbs::AbstractJob *doBuildOrClean(const qbs::Project &project, static qbs::AbstractJob *doBuildOrClean(const qbs::Project &project,
const QList<qbs::ProductData> &products, const QList<qbs::ProductData> &products,
const qbs::BuildOptions &options) const qbs::BuildOptions &options)
@@ -534,29 +529,8 @@ void QbsProject::handleRuleExecutionDone()
void QbsProject::changeActiveTarget(Target *t) void QbsProject::changeActiveTarget(Target *t)
{ {
BuildConfiguration *bc = 0; if (t)
if (t) {
m_qbsProject = m_qbsProjects.value(t); m_qbsProject = m_qbsProjects.value(t);
if (t->kit())
bc = t->activeBuildConfiguration();
}
buildConfigurationChanged(bc);
}
void QbsProject::buildConfigurationChanged(BuildConfiguration *bc)
{
if (m_currentBc)
disconnect(m_currentBc, &QbsBuildConfiguration::qbsConfigurationChanged,
this, &QbsProject::delayParsing);
m_currentBc = qobject_cast<QbsBuildConfiguration *>(bc);
if (m_currentBc) {
connect(m_currentBc, &QbsBuildConfiguration::qbsConfigurationChanged,
this, &QbsProject::delayParsing);
delayParsing();
} else {
invalidate();
}
} }
void QbsProject::startParsing() void QbsProject::startParsing()

View File

@@ -107,7 +107,6 @@ public:
void configureAsExampleProject(const QSet<Core::Id> &platforms) final; void configureAsExampleProject(const QSet<Core::Id> &platforms) final;
void invalidate();
void delayParsing(); void delayParsing();
private: private:
@@ -116,7 +115,6 @@ private:
void rebuildProjectTree(); void rebuildProjectTree();
void changeActiveTarget(ProjectExplorer::Target *t); void changeActiveTarget(ProjectExplorer::Target *t);
void buildConfigurationChanged(ProjectExplorer::BuildConfiguration *bc);
void startParsing(); void startParsing();
void parse(const QVariantMap &config, const Utils::Environment &env, const QString &dir, void parse(const QVariantMap &config, const Utils::Environment &env, const QString &dir,
@@ -165,7 +163,6 @@ private:
CppTools::CppProjectUpdater *m_cppCodeModelUpdater = nullptr; CppTools::CppProjectUpdater *m_cppCodeModelUpdater = nullptr;
CppTools::ProjectInfo m_cppCodeModelProjectInfo; CppTools::ProjectInfo m_cppCodeModelProjectInfo;
QbsBuildConfiguration *m_currentBc;
mutable ProjectExplorer::ProjectImporter *m_importer = nullptr; mutable ProjectExplorer::ProjectImporter *m_importer = nullptr;
QTimer m_parsingDelay; QTimer m_parsingDelay;

View File

@@ -57,6 +57,12 @@ void QmlProfilerClientManager::setFlushInterval(quint32 flushInterval)
m_flushInterval = flushInterval; m_flushInterval = flushInterval;
} }
void QmlProfilerClientManager::clearEvents()
{
if (m_clientPlugin)
m_clientPlugin->clearEvents();
}
void QmlProfilerClientManager::clearBufferedData() void QmlProfilerClientManager::clearBufferedData()
{ {
if (m_clientPlugin) if (m_clientPlugin)

View File

@@ -46,6 +46,7 @@ class QmlProfilerClientManager : public QmlDebug::QmlDebugConnectionManager
public: public:
explicit QmlProfilerClientManager(QObject *parent = 0); explicit QmlProfilerClientManager(QObject *parent = 0);
void setProfilerStateManager(QmlProfilerStateManager *profilerState); void setProfilerStateManager(QmlProfilerStateManager *profilerState);
void clearEvents();
void setModelManager(QmlProfilerModelManager *modelManager); void setModelManager(QmlProfilerModelManager *modelManager);
void setFlushInterval(quint32 flushInterval); void setFlushInterval(quint32 flushInterval);
void clearBufferedData(); void clearBufferedData();

View File

@@ -691,9 +691,8 @@ QmlProfilerModelManager::State QmlProfilerModelManager::state() const
return d->state; return d->state;
} }
void QmlProfilerModelManager::clear() void QmlProfilerModelManager::doClearEvents()
{ {
setState(ClearingData);
d->numLoadedEvents = 0; d->numLoadedEvents = 0;
d->numFinishedFinalizers = 0; d->numFinishedFinalizers = 0;
d->file.remove(); d->file.remove();
@@ -702,13 +701,25 @@ void QmlProfilerModelManager::clear()
d->eventStream.setDevice(&d->file); d->eventStream.setDevice(&d->file);
else else
emit error(tr("Cannot open temporary trace file to store events.")); emit error(tr("Cannot open temporary trace file to store events."));
d->eventTypes.clear();
d->detailsRewriter->clear();
d->traceTime->clear(); d->traceTime->clear();
d->notesModel->clear(); d->notesModel->clear();
setVisibleFeatures(0); setVisibleFeatures(0);
setRecordedFeatures(0); setRecordedFeatures(0);
}
void QmlProfilerModelManager::clearEvents()
{
setState(ClearingData);
doClearEvents();
setState(Empty);
}
void QmlProfilerModelManager::clear()
{
setState(ClearingData);
doClearEvents();
d->eventTypes.clear();
d->detailsRewriter->clear();
setState(Empty); setState(Empty);
} }

View File

@@ -134,6 +134,7 @@ public:
static const char *featureName(ProfileFeature feature); static const char *featureName(ProfileFeature feature);
void clearEvents();
void clear(); void clear();
void restrictToRange(qint64 startTime, qint64 endTime); void restrictToRange(qint64 startTime, qint64 endTime);
bool isRestrictedToRange() const; bool isRestrictedToRange() const;
@@ -156,6 +157,7 @@ signals:
private: private:
void setState(State state); void setState(State state);
void detailsChanged(int typeId, const QString &newString); void detailsChanged(int typeId, const QString &newString);
void doClearEvents();
class QmlProfilerModelManagerPrivate; class QmlProfilerModelManagerPrivate;
QmlProfilerModelManagerPrivate *d; QmlProfilerModelManagerPrivate *d;

View File

@@ -44,6 +44,7 @@
#include <utils/fancymainwindow.h> #include <utils/fancymainwindow.h>
#include <utils/fileinprojectfinder.h> #include <utils/fileinprojectfinder.h>
#include <utils/qtcassert.h> #include <utils/qtcassert.h>
#include <utils/url.h>
#include <utils/utilsicons.h> #include <utils/utilsicons.h>
#include <projectexplorer/environmentaspect.h> #include <projectexplorer/environmentaspect.h>
#include <projectexplorer/projectexplorer.h> #include <projectexplorer/projectexplorer.h>
@@ -406,7 +407,7 @@ void QmlProfilerTool::recordingButtonChanged(bool recording)
if (checkForUnsavedNotes()) { if (checkForUnsavedNotes()) {
if (!d->m_profilerModelManager->aggregateTraces() || if (!d->m_profilerModelManager->aggregateTraces() ||
d->m_profilerModelManager->state() == QmlProfilerModelManager::Done) d->m_profilerModelManager->state() == QmlProfilerModelManager::Done)
clearData(); // clear before the recording starts, unless we aggregate recordings clearEvents(); // clear before the recording starts, unless we aggregate recordings
if (d->m_profilerState->clientRecording()) if (d->m_profilerState->clientRecording())
d->m_profilerState->setClientRecording(false); d->m_profilerState->setClientRecording(false);
d->m_profilerState->setClientRecording(true); d->m_profilerState->setClientRecording(true);
@@ -471,6 +472,13 @@ void QmlProfilerTool::showTimeLineSearch()
Core::Find::openFindToolBar(Core::Find::FindForwardDirection); Core::Find::openFindToolBar(Core::Find::FindForwardDirection);
} }
void QmlProfilerTool::clearEvents()
{
d->m_profilerModelManager->clearEvents();
d->m_profilerConnections->clearEvents();
setRecordedFeatures(0);
}
void QmlProfilerTool::clearData() void QmlProfilerTool::clearData()
{ {
d->m_profilerModelManager->clear(); d->m_profilerModelManager->clear();
@@ -555,6 +563,7 @@ void QmlProfilerTool::attachToWaitingApplication()
IDevice::ConstPtr device = DeviceKitInformation::device(kit); IDevice::ConstPtr device = DeviceKitInformation::device(kit);
QTC_ASSERT(device, return); QTC_ASSERT(device, return);
QUrl toolControl = device->toolControlChannel(IDevice::QmlControlChannel); QUrl toolControl = device->toolControlChannel(IDevice::QmlControlChannel);
serverUrl.setScheme(Utils::urlTcpScheme());
serverUrl.setHost(toolControl.host()); serverUrl.setHost(toolControl.host());
serverUrl.setPort(port); serverUrl.setPort(port);
@@ -565,6 +574,8 @@ void QmlProfilerTool::attachToWaitingApplication()
auto profiler = new QmlProfilerRunner(runControl); auto profiler = new QmlProfilerRunner(runControl);
profiler->setServerUrl(serverUrl); profiler->setServerUrl(serverUrl);
connect(d->m_profilerConnections, &QmlProfilerClientManager::connectionClosed,
runControl, &RunControl::initiateStop);
ProjectExplorerPlugin::startRunControl(runControl); ProjectExplorerPlugin::startRunControl(runControl);
} }
@@ -858,7 +869,7 @@ void QmlProfilerTool::serverRecordingChanged()
d->m_recordingElapsedTime.start(); d->m_recordingElapsedTime.start();
if (!d->m_profilerModelManager->aggregateTraces() || if (!d->m_profilerModelManager->aggregateTraces() ||
d->m_profilerModelManager->state() == QmlProfilerModelManager::Done) d->m_profilerModelManager->state() == QmlProfilerModelManager::Done)
clearData(); clearEvents();
d->m_profilerModelManager->startAcquiring(); d->m_profilerModelManager->startAcquiring();
} else { } else {
d->m_recordingTimer.stop(); d->m_recordingTimer.stop();

View File

@@ -74,6 +74,7 @@ public:
void gotoSourceLocation(const QString &fileUrl, int lineNumber, int columnNumber); void gotoSourceLocation(const QString &fileUrl, int lineNumber, int columnNumber);
private: private:
void clearEvents();
void clearData(); void clearData();
void showErrorDialog(const QString &error); void showErrorDialog(const QString &error);
void profilerDataModelStateChanged(); void profilerDataModelStateChanged();

View File

@@ -227,10 +227,8 @@ QmlProfilerTraceClient::~QmlProfilerTraceClient()
delete d; delete d;
} }
void QmlProfilerTraceClient::clear() void QmlProfilerTraceClient::clearEvents()
{ {
d->serverTypeIds.clear();
d->eventTypeIds.clear();
d->rangesInProgress.clear(); d->rangesInProgress.clear();
d->pendingMessages.clear(); d->pendingMessages.clear();
d->pendingDebugMessages.clear(); d->pendingDebugMessages.clear();
@@ -241,6 +239,13 @@ void QmlProfilerTraceClient::clear()
emit cleared(); emit cleared();
} }
void QmlProfilerTraceClient::clear()
{
d->eventTypeIds.clear();
d->serverTypeIds.clear();
clearEvents();
}
void QmlProfilerTraceClient::sendRecordingStatus(int engineId) void QmlProfilerTraceClient::sendRecordingStatus(int engineId)
{ {
d->sendRecordingStatus(engineId); d->sendRecordingStatus(engineId);

View File

@@ -55,6 +55,7 @@ public:
virtual void messageReceived(const QByteArray &) override; virtual void messageReceived(const QByteArray &) override;
virtual void stateChanged(State status) override; virtual void stateChanged(State status) override;
void clearEvents();
void clear(); void clear();
void sendRecordingStatus(int engineId = -1); void sendRecordingStatus(int engineId = -1);
void setRequestedFeatures(quint64 features); void setRequestedFeatures(quint64 features);

View File

@@ -2,11 +2,12 @@ TEMPLATE = subdirs
SUBDIRS = qtpromaker \ SUBDIRS = qtpromaker \
../plugins/cpaster/frontend \ ../plugins/cpaster/frontend \
sdktool \
valgrindfake \ valgrindfake \
3rdparty \ 3rdparty \
buildoutputparser buildoutputparser
isEmpty(QTC_SKIP_SDKTOOL): SUBDIRS += sdktool
qtHaveModule(quick-private): SUBDIRS += qml2puppet qtHaveModule(quick-private): SUBDIRS += qml2puppet
win32 { win32 {

View File

@@ -68,16 +68,13 @@ def main():
treeFile = "projecttree_speedcrunch.tsv" treeFile = "projecttree_speedcrunch.tsv"
compareProjectTree(naviTreeView % "speedcrunch( \[\S+\])?", treeFile) compareProjectTree(naviTreeView % "speedcrunch( \[\S+\])?", treeFile)
if not cmakeSupportsServerMode() and JIRA.isBugStillOpen(18290): # Invoke a rebuild of the application
test.xfail("Building with cmake in Tealeafreader mode may fail", "QTCREATORBUG-18290") invokeMenuItem("Build", "Rebuild All")
else:
# Invoke a rebuild of the application
invokeMenuItem("Build", "Rebuild All")
# Wait for, and test if the build succeeded # Wait for, and test if the build succeeded
waitForCompile(300000) waitForCompile(300000)
checkCompile() checkCompile()
checkLastBuild() checkLastBuild()
invokeMenuItem("File", "Exit") invokeMenuItem("File", "Exit")