Commit 14e35b5d authored by Orgad Shaneh's avatar Orgad Shaneh Committed by Orgad Shaneh

Client: Block until editor is closed

Change-Id: I06bd4425008103be3a4c8f64b6dff8f7df30c552
Reviewed-by: default avatarLeena Miettinen <riitta-leena.miettinen@digia.com>
Reviewed-by: default avatarEike Ziller <eike.ziller@digia.com>
parent 225c21a0
......@@ -71,7 +71,8 @@ static const char fixedOptionsC[] =
" -version Display program version\n"
" -client Attempt to connect to already running first instance\n"
" -settingspath <path> Override the default path where user settings are stored\n"
" -pid <pid> Attempt to connect to instance given by pid\n";
" -pid <pid> Attempt to connect to instance given by pid\n"
" -block Block until editor is closed\n";
static const char HELP_OPTION1[] = "-h";
......@@ -82,6 +83,7 @@ static const char VERSION_OPTION[] = "-version";
static const char CLIENT_OPTION[] = "-client";
static const char SETTINGS_OPTION[] = "-settingspath";
static const char PID_OPTION[] = "-pid";
static const char BLOCK_OPTION[] = "-block";
typedef QList<PluginSpec *> PluginSpecSet;
......@@ -409,6 +411,7 @@ int main(int argc, char **argv)
appOptions.insert(QLatin1String(VERSION_OPTION), false);
appOptions.insert(QLatin1String(CLIENT_OPTION), false);
appOptions.insert(QLatin1String(PID_OPTION), true);
appOptions.insert(QLatin1String(BLOCK_OPTION), false);
QString errorMessage;
if (!PluginManager::parseOptions(arguments, appOptions, &foundAppOptions, &errorMessage)) {
displayError(errorMessage);
......@@ -456,7 +459,10 @@ int main(int argc, char **argv)
pid = tmpPid;
}
if (app.isRunning() && (pid != -1 || foundAppOptions.contains(QLatin1String(CLIENT_OPTION)))) {
bool isBlock = foundAppOptions.contains(QLatin1String(BLOCK_OPTION));
if (app.isRunning() && (pid != -1 || isBlock
|| foundAppOptions.contains(QLatin1String(CLIENT_OPTION)))) {
app.setBlock(isBlock);
if (app.sendMessage(PluginManager::serializedArguments(), 5000 /*timeout*/, pid))
return 0;
......@@ -489,8 +495,8 @@ int main(int argc, char **argv)
// Set up lock and remote arguments.
app.initialize();
QObject::connect(&app, SIGNAL(messageReceived(QString)),
&pluginManager, SLOT(remoteArguments(QString)));
QObject::connect(&app, SIGNAL(messageReceived(QString,QObject*)),
&pluginManager, SLOT(remoteArguments(QString,QObject*)));
QObject::connect(&app, SIGNAL(fileOpenRequest(QString)), coreplugin->plugin(),
SLOT(fileOpenRequest(QString)));
......
......@@ -157,6 +157,19 @@
\sa asynchronousShutdownFinished()
*/
/*!
\fn QObject *IPlugin::remoteCommand(const QStringList &options, const QStringList &arguments)
\brief When \QC is executed with the -client argument while already another instance of \QC
is running, this method of plugins is called in the running instance.
Plugin-specific arguments are passed in \a options, while the rest of the
arguments are passed in \a arguments.
\returns a QObject that blocks the command until it is destroyed, if -block is used.
\sa PluginManager::serializedArguments()
*/
/*!
\fn void IPlugin::asynchronousShutdownFinished()
Sent by the plugin implementation after a asynchronous shutdown
......
......@@ -64,7 +64,7 @@ public:
virtual void extensionsInitialized() = 0;
virtual bool delayedInitialize() { return false; }
virtual ShutdownFlag aboutToShutdown() { return SynchronousShutdown; }
virtual void remoteCommand(const QStringList & /* options */, const QStringList & /* arguments */) { }
virtual QObject *remoteCommand(const QStringList & /* options */, const QStringList & /* arguments */) { return 0; }
PluginSpec *pluginSpec() const;
......
......@@ -532,13 +532,16 @@ static QStringList subList(const QStringList &in, const QString &key)
}
/*!
\fn PluginManager::remoteArguments(const QString &argument)
\fn PluginManager::remoteArguments(const QString &argument, QObject *socket)
Parses the options encoded by serializedArguments() const
and passes them on to the respective plugins along with the arguments.
\a socket is passed for disconnecting the peer when the operation is done (for example,
document is closed) for supporting the -block flag.
*/
void PluginManager::remoteArguments(const QString &serializedArgument)
void PluginManager::remoteArguments(const QString &serializedArgument, QObject *socket)
{
if (serializedArgument.isEmpty())
return;
......@@ -547,9 +550,15 @@ void PluginManager::remoteArguments(const QString &serializedArgument)
foreach (const PluginSpec *ps, plugins()) {
if (ps->state() == PluginSpec::Running) {
const QStringList pluginOptions = subList(serializedArguments, QLatin1Char(':') + ps->name());
ps->plugin()->remoteCommand(pluginOptions, arguments);
QObject *socketParent = ps->plugin()->remoteCommand(pluginOptions, arguments);
if (socketParent && socket) {
socket->setParent(socketParent);
socket = 0;
}
}
}
if (socket)
delete socket;
}
/*!
......
......@@ -137,7 +137,7 @@ signals:
void initializationDone();
public slots:
void remoteArguments(const QString &serializedArguments);
void remoteArguments(const QString &serializedArguments, QObject *socket);
void shutdown();
private slots:
......
......@@ -119,10 +119,12 @@ bool CorePlugin::delayedInitialize()
return true;
}
void CorePlugin::remoteCommand(const QStringList & /* options */, const QStringList &args)
QObject *CorePlugin::remoteCommand(const QStringList & /* options */, const QStringList &args)
{
m_mainWindow->openFiles(args, Core::ICore::OpenFilesFlags(ICore::SwitchMode | ICore::CanContainLineNumbers));
IDocument *res = m_mainWindow->openFiles(
args, ICore::OpenFilesFlags(ICore::SwitchMode | ICore::CanContainLineNumbers));
m_mainWindow->activateWindow();
return res;
}
void CorePlugin::fileOpenRequest(const QString &f)
......
......@@ -52,7 +52,7 @@ public:
void extensionsInitialized();
bool delayedInitialize();
ShutdownFlag aboutToShutdown();
void remoteCommand(const QStringList & /* options */, const QStringList &args);
QObject *remoteCommand(const QStringList & /* options */, const QStringList &args);
public slots:
void fileOpenRequest(const QString&);
......
......@@ -831,31 +831,51 @@ static IDocumentFactory *findDocumentFactory(const QList<IDocumentFactory*> &fil
return 0;
}
// opens either an editor or loads a project
void MainWindow::openFiles(const QStringList &fileNames, ICore::OpenFilesFlags flags)
/*! Either opens \a fileNames with editors or loads a project.
*
* \a flags can be used to stop on first failure, indicate that a file name
* might include line numbers and/or switch mode to edit mode.
*
* \returns the first opened document. Required to support the -block flag
* for client mode.
*
* \sa IPlugin::remoteArguments()
*/
IDocument *MainWindow::openFiles(const QStringList &fileNames, ICore::OpenFilesFlags flags)
{
QList<IDocumentFactory*> nonEditorFileFactories = getNonEditorDocumentFactories();
IDocument *res = 0;
foreach (const QString &fileName, fileNames) {
const QFileInfo fi(fileName);
const QString absoluteFilePath = fi.absoluteFilePath();
if (IDocumentFactory *documentFactory = findDocumentFactory(nonEditorFileFactories, mimeDatabase(), fi)) {
Core::IDocument *document = documentFactory->open(absoluteFilePath);
if (!document && (flags & ICore::StopOnLoadFail))
return;
if (document && (flags & ICore::SwitchMode))
ModeManager::activateMode(Id(Core::Constants::MODE_EDIT));
IDocument *document = documentFactory->open(absoluteFilePath);
if (!document) {
if (flags & ICore::StopOnLoadFail)
return res;
} else {
if (!res)
res = document;
if (flags & ICore::SwitchMode)
ModeManager::activateMode(Id(Core::Constants::MODE_EDIT));
}
} else {
QFlags<EditorManager::OpenEditorFlag> emFlags;
if (flags & ICore::SwitchMode)
emFlags = EditorManager::ModeSwitch;
if (flags & ICore::CanContainLineNumbers)
emFlags |= EditorManager::CanContainLineNumber;
Core::IEditor *editor = EditorManager::openEditor(absoluteFilePath, Id(), emFlags);
if (!editor && (flags & ICore::StopOnLoadFail))
return;
IEditor *editor = EditorManager::openEditor(absoluteFilePath, Id(), emFlags);
if (!editor) {
if (flags & ICore::StopOnLoadFail)
return res;
} else if (!res) {
res = editor->document();
}
}
}
return res;
}
void MainWindow::setFocusToEditor()
......
......@@ -53,6 +53,7 @@ class EditorManager;
class ExternalToolManager;
class DocumentManager;
class HelpManager;
class IDocument;
class IWizard;
class MessageManager;
class MimeDatabase;
......@@ -95,7 +96,7 @@ public:
void removeContextObject(IContext *contex);
void resetContext();
void openFiles(const QStringList &fileNames, ICore::OpenFilesFlags flags);
Core::IDocument *openFiles(const QStringList &fileNames, ICore::OpenFilesFlags flags);
Core::ActionManager *actionManager() const;
Core::MessageManager *messageManager() const;
......
......@@ -3441,10 +3441,11 @@ IPlugin::ShutdownFlag DebuggerPlugin::aboutToShutdown()
return SynchronousShutdown;
}
void DebuggerPlugin::remoteCommand(const QStringList &options,
QObject *DebuggerPlugin::remoteCommand(const QStringList &options,
const QStringList &list)
{
theDebuggerCore->remoteCommand(options, list);
return 0;
}
DebuggerRunControl *DebuggerPlugin::createDebugger
......
......@@ -71,7 +71,7 @@ public:
private:
// IPlugin implementation.
bool initialize(const QStringList &arguments, QString *errorMessage);
void remoteCommand(const QStringList &options, const QStringList &arguments);
QObject *remoteCommand(const QStringList &options, const QStringList &arguments);
ShutdownFlag aboutToShutdown();
void extensionsInitialized();
......
......@@ -99,7 +99,7 @@ bool QtLocalPeer::isClient()
return false;
}
bool QtLocalPeer::sendMessage(const QString &message, int timeout)
bool QtLocalPeer::sendMessage(const QString &message, int timeout, bool block)
{
if (!isClient())
return false;
......@@ -129,6 +129,8 @@ bool QtLocalPeer::sendMessage(const QString &message, int timeout)
bool res = socket.waitForBytesWritten(timeout);
res &= socket.waitForReadyRead(timeout); // wait for ack
res &= (socket.read(qstrlen(ack)) == ack);
if (block) // block until peer disconnects
socket.waitForDisconnected(-1);
return res;
}
......@@ -168,8 +170,7 @@ void QtLocalPeer::receiveConnection()
QString message = QString::fromUtf8(uMsg.constData(), uMsg.size());
socket->write(ack, qstrlen(ack));
socket->waitForBytesWritten(1000);
delete socket;
emit messageReceived(message); // ##(might take a long time to return)
emit messageReceived(message, socket); // ##(might take a long time to return)
}
} // namespace SharedTools
......@@ -42,12 +42,12 @@ class QtLocalPeer : public QObject
public:
explicit QtLocalPeer(QObject *parent = 0, const QString &appId = QString());
bool isClient();
bool sendMessage(const QString &message, int timeout);
bool sendMessage(const QString &message, int timeout, bool block);
QString applicationId() const
{ return id; }
Q_SIGNALS:
void messageReceived(const QString &message);
void messageReceived(const QString &message, QObject *socket);
protected Q_SLOTS:
void receiveConnection();
......
......@@ -38,10 +38,11 @@ namespace SharedTools {
void QtSingleApplication::sysInit(const QString &appId)
{
actWin = 0;
block = false;
firstPeer = new QtLocalPeer(this, appId);
connect(firstPeer, SIGNAL(messageReceived(QString)), SIGNAL(messageReceived(QString)));
connect(firstPeer, SIGNAL(messageReceived(QString,QObject*)), SIGNAL(messageReceived(QString,QObject*)));
pidPeer = new QtLocalPeer(this, appId + QLatin1Char('-') + QString::number(QCoreApplication::applicationPid(), 10));
connect(pidPeer, SIGNAL(messageReceived(QString)), SIGNAL(messageReceived(QString)));
connect(pidPeer, SIGNAL(messageReceived(QString,QObject*)), SIGNAL(messageReceived(QString,QObject*)));
}
......@@ -87,10 +88,10 @@ void QtSingleApplication::initialize(bool)
bool QtSingleApplication::sendMessage(const QString &message, int timeout, qint64 pid)
{
if (pid == -1)
return firstPeer->sendMessage(message, timeout);
return firstPeer->sendMessage(message, timeout, block);
QtLocalPeer peer(this, appId + QLatin1Char('-') + QString::number(pid, 10));
return peer.sendMessage(message, timeout);
return peer.sendMessage(message, timeout, block);
}
QString QtSingleApplication::id() const
......@@ -103,15 +104,20 @@ QString QtSingleApplication::applicationId() const
return appId;
}
void QtSingleApplication::setBlock(bool value)
{
block = value;
}
void QtSingleApplication::setActivationWindow(QWidget *aw, bool activateOnMessage)
{
actWin = aw;
if (activateOnMessage) {
connect(firstPeer, SIGNAL(messageReceived(QString)), this, SLOT(activateWindow()));
connect(pidPeer, SIGNAL(messageReceived(QString)), this, SLOT(activateWindow()));
connect(firstPeer, SIGNAL(messageReceived(QString,QObject*)), this, SLOT(activateWindow()));
connect(pidPeer, SIGNAL(messageReceived(QString,QObject*)), this, SLOT(activateWindow()));
} else {
disconnect(firstPeer, SIGNAL(messageReceived(QString)), this, SLOT(activateWindow()));
disconnect(pidPeer, SIGNAL(messageReceived(QString)), this, SLOT(activateWindow()));
disconnect(firstPeer, SIGNAL(messageReceived(QString,QObject*)), this, SLOT(activateWindow()));
disconnect(pidPeer, SIGNAL(messageReceived(QString,QObject*)), this, SLOT(activateWindow()));
}
}
......
......@@ -50,6 +50,7 @@ public:
bool event(QEvent *event);
QString applicationId() const;
void setBlock(bool value);
public Q_SLOTS:
bool sendMessage(const QString &message, int timeout = 5000, qint64 pid = -1);
......@@ -61,7 +62,7 @@ public:
// end obsolete methods
Q_SIGNALS:
void messageReceived(const QString &message);
void messageReceived(const QString &message, QObject *socket);
void fileOpenRequest(const QString &file);
private:
......@@ -70,6 +71,7 @@ private:
QtLocalPeer *pidPeer;
QWidget *actWin;
QString appId;
bool block;
};
} // namespace SharedTools
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