1 /*
2 * Copyright (C) 2008 Martin Hostettler
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version 2
7 * of the License, or (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
16 *
17 */
18
19 // manager mini command system
20
21 #include <QDebug>
22
23 #include "mcmdmanager.h"
24
25
MCmdSimpleState(QString name,QString prompt)26 MCmdSimpleState::MCmdSimpleState(QString name, QString prompt) {
27 name_ = name;
28 prompt_ = prompt;
29 }
30
MCmdSimpleState(QString name,QString prompt,int flags)31 MCmdSimpleState::MCmdSimpleState(QString name, QString prompt, int flags) {
32 name_ = name;
33 prompt_ = prompt;
34 flags_ = flags;
35 }
36
37
~MCmdSimpleState()38 MCmdSimpleState::~MCmdSimpleState() {
39 }
40
MCmdManager(MCmdUiSiteIface * site_)41 MCmdManager::MCmdManager(MCmdUiSiteIface* site_) : state_(0), uiSite_(site_) {
42 };
43
~MCmdManager()44 MCmdManager::~MCmdManager() {
45 foreach(MCmdProviderIface *prov, providers_) {
46 prov->mCmdSiteDestroyed();
47 }
48 }
49
50
parseCommand(const QString command,int pos,int & part,QString & partial,int & start,int & end,char & quotedAtPos)51 QStringList MCmdManager::parseCommand(const QString command, int pos, int &part, QString &partial, int &start, int &end, char "edAtPos)
52 {
53 QStringList list;
54 QString item;
55 bool escape=false;
56 int quote=0; // "=1, '=2
57 bool space=true;
58
59 int partStart = 0;
60 quotedAtPos = 0;
61 for (int i=0; i < command.length(); i++) {
62 if (i == pos) {
63 part = list.size();
64 partial = item;
65 end = i;
66 start = partStart;
67 if (quote) quotedAtPos = (quote == 1) ? '"' : '\'';
68 }
69
70
71 QChar ch = command[i];
72 if (escape) {
73 escape = false;
74 item += ch;
75 } else if (ch == '\\') {
76 escape = true;
77 } else if (quote != 0) {
78 if ((quote == 1 && ch == '"') || (quote == 2 && ch == '\'')) {
79 quote = 0;
80 } else {
81 item += ch;
82 }
83 } else if (ch == ' ') {
84 partStart = i+1;
85 if (space) {
86 continue;
87 }
88 list << item;
89 item = "";
90 space = true;
91 continue;
92 } else if (ch == '\'') {
93 quote = 2;
94 } else if (ch == '"') {
95 quote = 1;
96 } else {
97 item += ch;
98 }
99 space = false;
100 }
101 if (command.length() == pos) {
102 part = list.size();
103 partial = item;
104 end = command.length();
105 start = partStart;
106 if (quote) quotedAtPos = (quote == 1) ? '"' : '\'';
107 }
108
109 if (!space) list << item;
110 return list;
111 }
112
serializeCommand(const QStringList & list)113 QString MCmdManager::serializeCommand(const QStringList &list)
114 {
115 QString retval;
116 bool needspace = false;
117 QRegExp specials("([\"\'\\\\ ])");
118 foreach(QString item, list) {
119 item.replace(specials, "\\\\1");
120 if (item == "") item = "\"\"";
121 if (needspace) retval += " ";
122 retval += item;
123 needspace = true;
124 }
125 return retval;
126 }
127
128
processCommand(QString command)129 bool MCmdManager::processCommand(QString command) {
130 MCmdStateIface *tmpstate=0;
131 QStringList preset;
132 QStringList items;
133 if (state_->getFlags() & MCMDSTATE_UNPARSED) {
134 items << command;
135 } else {
136 int tmp_1;
137 QString tmp_2;
138 char tmp_3;
139 items = parseCommand(command, -1, tmp_1, tmp_2, tmp_1, tmp_1, tmp_3);
140 }
141 foreach(MCmdProviderIface *prov, providers_) {
142 if (prov->mCmdTryStateTransit(state_, items, tmpstate, preset)) {
143 state_ = tmpstate;
144 if (state_ != 0) {
145 QString prompt = state_->getPrompt();
146 QString def;
147 if (state_->getFlags() & MCMDSTATE_UNPARSED) {
148 if (preset.size() == 1) {
149 def = preset.at(0);
150 }
151 } else {
152 def = serializeCommand(preset);
153 }
154 uiSite_->mCmdReady(prompt, def);
155 } else {
156 uiSite_->mCmdClose();
157 }
158 return true;
159 }
160 }
161
162 tmpstate = state_;
163 bool ret = state_->unhandled(items);
164 state_ = 0;
165 if (state_ == 0) {
166 tmpstate->dispose();
167 uiSite_->mCmdClose();
168 }
169 return ret;
170 }
171
172
open(MCmdStateIface * state,QStringList preset)173 bool MCmdManager::open(MCmdStateIface *state, QStringList preset) {
174 if (0 != state_) state_->dispose();
175
176 state_ = state;
177 QString prompt = state->getPrompt();
178 QString def;
179 if (state_->getFlags() & MCMDSTATE_UNPARSED) {
180 if (preset.size() == 1) def = preset.at(0);
181 } else {
182 def = serializeCommand(preset);
183 }
184 uiSite_->mCmdReady(prompt, def);
185 return true;
186 }
187
188
completeCommand(QString & command,int pos,int & start,int & end)189 QStringList MCmdManager::completeCommand(QString &command, int pos, int &start, int &end) {
190 int part;
191 QString query;
192 char quotedAtPos;
193 QStringList all;
194 if (state_->getFlags() & MCMDSTATE_UNPARSED) {
195 all << command;
196 query = command.left(pos);
197 part = -1;
198 } else {
199 all = parseCommand(command, pos, part, query, start, end, quotedAtPos);
200 }
201
202 QStringList res;
203 foreach(MCmdProviderIface *prov, providers_) {
204 res += prov->mCmdTryCompleteCommand(state_, query, all, part);
205 }
206 res.sort();
207
208 QStringList quoted;
209 if ((state_->getFlags() & MCMDSTATE_UNPARSED) == 0) {
210 foreach(QString str, res) {
211 QString trail;
212 if (str.size() > 1 && str.at(str.size()-1) == QChar(0)) {
213 str.chop(1);
214 trail = " ";
215 }
216 str = str.replace("\\", "\\\\");
217 if (quotedAtPos == 0) {
218 quoted << str.replace(" ", "\\ ").replace("\"", "\\\"").replace("'", "\\'") + trail;
219 } else {
220 quoted << quotedAtPos + str.replace(quotedAtPos, QString("\\") + quotedAtPos) + trail;
221 }
222 }
223 } else {
224 quoted = res;
225 }
226 return quoted;
227 }
228
isActive()229 bool MCmdManager::isActive() {
230 return state_ != 0;
231 }
232
233
234
registerProvider(MCmdProviderIface * prov)235 void MCmdManager::registerProvider(MCmdProviderIface *prov)
236 {
237 if (! providers_.contains(prov)) {
238 providers_ += prov;
239 }
240 }
241