OSDN Git Service

611001e0dde3df94b194475d075226fca17a5dea
[qt-creator-jp/qt-creator-jp.git] / src / plugins / qt4projectmanager / qt-maemo / maemoremoteprocesslist.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: Nokia Corporation (qt-info@nokia.com)
6 **
7 ** This file is part of Qt Creator.
8 **
9 ** $QT_BEGIN_LICENSE:LGPL$
10 ** No Commercial Usage
11 ** This file contains pre-release code and may not be distributed.
12 ** You may use this file in accordance with the terms and conditions
13 ** contained in the Technology Preview License Agreement accompanying
14 ** this package.
15 **
16 ** GNU Lesser General Public License Usage
17 ** Alternatively, this file may be used under the terms of the GNU Lesser
18 ** General Public License version 2.1 as published by the Free Software
19 ** Foundation and appearing in the file LICENSE.LGPL included in the
20 ** packaging of this file.  Please review the following information to
21 ** ensure the GNU Lesser General Public License version 2.1 requirements
22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
23 **
24 ** In addition, as a special exception, Nokia gives you certain additional
25 ** rights.  These rights are described in the Nokia Qt LGPL Exception
26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
27 **
28 ** If you have questions regarding the use of this file, please contact
29 ** Nokia at qt-info@nokia.com.
30 **
31 **
32 **
33 **
34 **
35 **
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41
42 #include "maemoremoteprocesslist.h"
43
44 #include "maemodeviceconfigurations.h"
45
46 #include <utils/ssh/sshremoteprocessrunner.h>
47
48 #include <QtCore/QStringList>
49
50 using namespace Utils;
51
52 namespace Qt4ProjectManager {
53 namespace Internal {
54 namespace {
55 const QByteArray LineSeparator1("---");
56 const QByteArray LineSeparator2("QTCENDOFLINE---");
57 const QByteArray LineSeparator = LineSeparator1 + LineSeparator2;
58 } // anonymous namespace
59
60 MaemoRemoteProcessList::MaemoRemoteProcessList(const MaemoDeviceConfig::ConstPtr &devConfig,
61     QObject *parent)
62         : QAbstractTableModel(parent),
63           m_process(SshRemoteProcessRunner::create(devConfig->sshParameters())),
64           m_state(Inactive),
65           m_devConfig(devConfig)
66 {
67 }
68
69 MaemoRemoteProcessList::~MaemoRemoteProcessList() {}
70
71 void MaemoRemoteProcessList::update()
72 {
73     if (m_state != Inactive) {
74         qDebug("%s: Did not expect state to be %d.", Q_FUNC_INFO, m_state);
75         stop();
76     }
77     beginResetModel();
78     m_remoteProcs.clear();
79     QByteArray command;
80
81     // The ps command on Fremantle ignores all command line options, so
82     // we have to collect the information in /proc manually.
83     if (m_devConfig->osVersion() == MaemoGlobal::Maemo5) {
84         command = "sep1=" + LineSeparator1 + '\n'
85             + "sep2=" + LineSeparator2 + '\n'
86             + "pidlist=`ls /proc |grep -E '^[[:digit:]]+$' |sort -n`; "
87             +  "for pid in $pidlist\n"
88             +  "do\n"
89             +  "    echo -n \"$pid \"\n"
90             +  "    tr '\\0' ' ' < /proc/$pid/cmdline\n"
91             +  "    echo -n \"$sep1$sep2\"\n"
92             +  "done\n"
93             +  "echo ''";
94     } else {
95         command = "ps -eo pid,args";
96     }
97
98     startProcess(command, Listing);
99 }
100
101 void MaemoRemoteProcessList::killProcess(int row)
102 {
103     Q_ASSERT(row >= 0 && row < m_remoteProcs.count());
104     const QByteArray command
105         = "kill -9 " + QByteArray::number(m_remoteProcs.at(row).pid);
106     startProcess(command, Killing);
107 }
108
109 void MaemoRemoteProcessList::startProcess(const QByteArray &cmdLine,
110     State newState)
111 {
112     if (m_state != Inactive) {
113         qDebug("%s: Did not expect state to be %d.", Q_FUNC_INFO, m_state);
114         stop();
115     }
116     m_state = newState;
117     connect(m_process.data(), SIGNAL(connectionError(Utils::SshError)),
118         SLOT(handleConnectionError()));
119     connect(m_process.data(), SIGNAL(processOutputAvailable(QByteArray)),
120         SLOT(handleRemoteStdOut(QByteArray)));
121     connect(m_process.data(),
122         SIGNAL(processErrorOutputAvailable(QByteArray)),
123         SLOT(handleRemoteStdErr(QByteArray)));
124     connect(m_process.data(), SIGNAL(processClosed(int)),
125         SLOT(handleRemoteProcessFinished(int)));
126     m_remoteStdout.clear();
127     m_remoteStderr.clear();
128     m_errorMsg.clear();
129     m_process->run(cmdLine);
130 }
131
132 void MaemoRemoteProcessList::handleConnectionError()
133 {
134     if (m_state == Inactive)
135         return;
136
137     emit error(tr("Connection failure: %1")
138         .arg(m_process->connection()->errorString()));
139     stop();
140 }
141
142 void MaemoRemoteProcessList::handleRemoteStdOut(const QByteArray &output)
143 {
144     if (m_state == Listing)
145         m_remoteStdout += output;
146 }
147
148 void MaemoRemoteProcessList::handleRemoteStdErr(const QByteArray &output)
149 {
150     if (m_state != Inactive)
151         m_remoteStderr += output;
152 }
153
154 void MaemoRemoteProcessList::handleRemoteProcessFinished(int exitStatus)
155 {
156     if (m_state == Inactive)
157         return;
158
159     switch (exitStatus) {
160     case SshRemoteProcess::FailedToStart:
161         m_errorMsg = tr("Error: Remote process failed to start: %1")
162             .arg(m_process->process()->errorString());
163         break;
164     case SshRemoteProcess::KilledBySignal:
165         m_errorMsg = tr("Error: Remote process crashed: %1")
166             .arg(m_process->process()->errorString());
167         break;
168     case SshRemoteProcess::ExitedNormally:
169         if (m_process->process()->exitCode() == 0) {
170             if (m_state == Listing)
171                 buildProcessList();
172         } else {
173             m_errorMsg = tr("Remote process failed.");
174         }
175         break;
176     default:
177         Q_ASSERT_X(false, Q_FUNC_INFO, "Invalid exit status");
178     }
179
180     if (!m_errorMsg.isEmpty()) {
181         if (!m_remoteStderr.isEmpty()) {
182             m_errorMsg += tr("\nRemote stderr was: %1")
183                 .arg(QString::fromUtf8(m_remoteStderr));
184         }
185         emit error(m_errorMsg);
186     }
187     stop();
188 }
189
190 void MaemoRemoteProcessList::stop()
191 {
192     if (m_state == Inactive)
193         return;
194
195     disconnect(m_process.data(), 0, this, 0);
196     if (m_state == Listing)
197         endResetModel();
198     else if (m_errorMsg.isEmpty())
199         emit processKilled();
200     m_state = Inactive;
201 }
202
203 void MaemoRemoteProcessList::buildProcessList()
204 {
205     const bool isFremantle = m_devConfig->osVersion() == MaemoGlobal::Maemo5;
206     const QString remoteOutput = QString::fromUtf8(m_remoteStdout);
207     const QByteArray lineSeparator = isFremantle ? LineSeparator : "\n";
208     QStringList lines = remoteOutput.split(QString::fromUtf8(lineSeparator));
209     if (!isFremantle)
210         lines.removeFirst(); // column headers
211     foreach (const QString &line, lines) {
212         const QString &trimmedLine = line.trimmed();
213         const int pidEndPos = trimmedLine.indexOf(' ');
214         if (pidEndPos == -1)
215             continue;
216         bool isNumber;
217         const int pid = trimmedLine.left(pidEndPos).toInt(&isNumber);
218         if (!isNumber) {
219             qDebug("%s: Non-integer value where pid was expected. Line was: '%s'",
220                 Q_FUNC_INFO, qPrintable(trimmedLine));
221             continue;
222         }
223         m_remoteProcs << RemoteProc(pid, trimmedLine.mid(pidEndPos));
224     }
225 }
226
227 int MaemoRemoteProcessList::rowCount(const QModelIndex &parent) const
228 {
229     return parent.isValid() ? 0 : m_remoteProcs.count();
230 }
231
232 int MaemoRemoteProcessList::columnCount(const QModelIndex &parent) const
233 {
234     Q_UNUSED(parent);
235     return 2;
236 }
237
238 QVariant MaemoRemoteProcessList::headerData(int section,
239     Qt::Orientation orientation, int role) const
240 {
241     if (orientation != Qt::Horizontal || role != Qt::DisplayRole
242             || section < 0 || section >= columnCount())
243         return QVariant();
244     if (section == 0)
245         return tr("PID");
246     else
247         return tr("Command Line");
248 }
249
250 QVariant MaemoRemoteProcessList::data(const QModelIndex &index, int role) const
251 {
252     if (!index.isValid() || index.row() >= rowCount(index.parent())
253             || index.column() >= columnCount() || role != Qt::DisplayRole)
254         return QVariant();
255     const RemoteProc &proc = m_remoteProcs.at(index.row());
256     if (index.column() == 0)
257         return proc.pid;
258     else
259         return proc.cmdLine;
260 }
261
262 } // namespace Internal
263 } // namespace Qt4ProjectManager