00001
00002
00003
00004
00005
00006 #include "inputbar.h"
00007
00008 extern "C" {
00009 #include <assert.h>
00010 #include <stdlib.h>
00011 }
00012
00013 #include "action.h"
00014 #include "actions.h"
00015 #include "binder.h"
00016 #include "kernel.h"
00017 #include "label.h"
00018 #include "logger.h"
00019 #include "monitor.h"
00020 #include "prompt.h"
00021 #include "theme.h"
00022 #include "workspace.h"
00023 #include "xcore.h"
00024
00025 InputBar::InputBar(Monitor *monitor, Rectangle *rect)
00026 : Bar(monitor, rect)
00027 {
00028
00029 LOGDEBUG("initializing input");
00030 currAction_ = 0;
00031 prompt_ = 0;
00032 promptCounter_ = 0;
00033 isArgument_ = false;
00034 entryBegin_ = entryEnd_ = 0;
00035 partitionBegin_ = selected_ = entryBegin_;
00036 args_ = "";
00037 LOGDEBUG("creating input");
00038 }
00039
00040 InputBar::~InputBar() {
00041 }
00042
00043 void InputBar::selectPrevEntry() {
00044
00045 if (entryBegin_ == entryEnd_) {
00046
00047 return;
00048 }
00049
00050 if (selected_ != partitionBegin_) {
00051 selected_--;
00052 }
00053 else {
00054
00055 if (partitionBegin_ != entryBegin_) {
00056
00057 selected_ = --partitionBegin_;
00058 partitionBegin_ = prevPartitions_.top();
00059 prevPartitions_.pop();
00060 }
00061 else {
00062 clearPrevPartitionsStack();
00063 }
00064 }
00065 }
00066
00067 void InputBar::selectNextEntry() {
00068
00069 if (entryBegin_ == entryEnd_) {
00070
00071 return;
00072 }
00073
00074 Sstring::iterator tmp = selected_;
00075 selected_++;
00076
00077 if (selected_ == entryEnd_) {
00078 selected_ = partitionBegin_ = entryBegin_;
00079 clearPrevPartitionsStack();
00080 return;
00081 }
00082
00083 if (tmp == partitionEnd_) {
00084 prevPartitions_.push(partitionBegin_);
00085 partitionBegin_ = selected_;
00086 }
00087 }
00088
00089 void InputBar::illuminate() {
00090
00091 if (!isVisible()) {
00092 return;
00093 }
00094
00095 drawBorder();
00096 LOGDEBUG("input update");
00097
00098
00099 label_->setAlignment(Label::CENTER);
00100 label_->setText("");
00101 label_->setX(1);
00102 label_->setWidth(width() - 2);
00103 label_->update(theme_->BAR_BACKGROUND, theme_->BAR_TEXT,
00104 theme_->BAR_SHINE, theme_->BAR_SHADOW);
00105
00106
00107 label_->setText(prompt_ ? prompt_->prompt() : "");
00108 label_->adjustWidth();
00109 label_->update(theme_->BAR_BACKGROUND, theme_->BAR_TEXT,
00110 theme_->BAR_SHINE, theme_->BAR_SHADOW);
00111 label_->setX(label_->x() + label_->width());
00112
00113
00114 label_->setText(text_);
00115 label_->adjustWidth();
00116 label_->update(theme_->BAR_BACKGROUND, theme_->BAR_TEXT,
00117 theme_->BAR_SHINE, theme_->BAR_SHADOW);
00118 label_->setX(label_->x() + label_->width());
00119
00120 if (partitionBegin_ != entryBegin_) {
00121 label_->setText("<<");
00122 label_->adjustWidth();
00123 label_->update(theme_->BAR_BACKGROUND, theme_->BAR_TEXT,
00124 theme_->BAR_SHINE, theme_->BAR_SHADOW);
00125 label_->setX(label_->x() + label_->width());
00126 }
00127
00128 label_->setText(">>");
00129 unsigned int nextWidth = label_->adjustWidth();
00130
00131 for (Sstring::iterator it = partitionBegin_; it != entryEnd_; it++)
00132 {
00133 string currStr = *it;
00134 label_->setText(currStr);
00135 label_->adjustWidth();
00136
00137
00138 if (label_->x() + label_->width() < (width() - nextWidth)) {
00139
00140 if (selected_ != it) {
00141 label_->update(theme_->LABEL_BACKGROUND_NORMAL,
00142 theme_->LABEL_TEXT_NORMAL,
00143 theme_->LABEL_SHINE_NORMAL,
00144 theme_->LABEL_SHADOW_NORMAL);
00145 }
00146 else {
00147 label_->update(theme_->LABEL_BACKGROUND_FOCUSSED,
00148 theme_->LABEL_TEXT_FOCUSSED,
00149 theme_->LABEL_SHINE_FOCUSSED,
00150 theme_->LABEL_SHADOW_FOCUSSED,
00151 true, true);
00152 }
00153 }
00154 else {
00155 partitionEnd_ = --it;
00156 label_->setText(">>");
00157 label_->adjustWidth();
00158 label_->update(theme_->BAR_BACKGROUND, theme_->BAR_TEXT,
00159 theme_->BAR_SHINE, theme_->BAR_SHADOW);
00160 break;
00161 }
00162 label_->setX(label_->x() + label_->width());
00163 }
00164 }
00165
00166 string InputBar::text(bool onExecEnter) {
00167
00168 if ((selected_ == entryBegin_) && (entryBegin_ == entryEnd_)) {
00169 return text_;
00170 }
00171 else {
00172
00173 if (onExecEnter && (text_.length() > 0) && (text_[0] == '/')) {
00174 text_ = text_.substr(0, text_.find_last_of('/') + 1);
00175 return text_ + *selected_;
00176 }
00177 return *selected_;
00178 }
00179 }
00180
00181 void InputBar::clearPrevPartitionsStack() {
00182 while (!prevPartitions_.empty()) {
00183 prevPartitions_.pop();
00184 }
00185 }
00186
00187 void InputBar::removeChar() {
00188
00189 if (!isVisible() || !prompt_) {
00190 return;
00191 }
00192
00193 int textLength = text_.length();
00194 if (textLength < 1) {
00195 return;
00196 }
00197
00198 if (prompt_->toQuery() && names_.size()>0) {
00199 unsigned int numNames = names_.size();
00200 for (; (numNames == names_.size()) && (textLength >= 0);
00201 textLength--)
00202 {
00203 #ifdef POSIX_REGEX
00204 string s = Binder::instance()->popRegexPattern();
00205 LOGDEBUG("popping from STACK: " + s);
00206 queryText(s);
00207 textLength=s.length();
00208 #else
00209 queryText(text_.substr(0, textLength));
00210 #endif
00211 }
00212 }
00213 else {
00214 queryText(text_.substr(0, textLength - 1));
00215 }
00216 illuminate();
00217 }
00218
00219 void InputBar::queryText(string text) {
00220
00221 if (!isVisible() || !prompt_) {
00222 return;
00223 }
00224
00225 QueryNamesForPrefix toQuery = prompt_->toQuery();
00226 names_.clear();
00227
00228 if (toQuery) {
00229 text_ = ((*Binder::instance()).*toQuery)(text, &names_);
00230 entryBegin_ = names_.begin();
00231 entryEnd_ = names_.end();;
00232 selected_ = partitionBegin_ = entryBegin_;
00233 clearPrevPartitionsStack();
00234 }
00235 else {
00236 entryBegin_ = entryEnd_ = 0;
00237 partitionBegin_ = selected_ = entryBegin_;
00238 text_ = text;
00239 }
00240 }
00241
00242 void InputBar::handleInput(XKeyEvent *event) {
00243
00244 static const char *home = getenv("HOME");
00245 static bool isNext = false;
00246 char buffer[32];
00247 int count;
00248
00249 if (!isVisible()) {
00250 return;
00251 }
00252 static KeySym sym;
00253
00254 sym = XCORE->lookupNextKeySym(event, &count, buffer);
00255 if (IsFunctionKey(sym) || IsKeypadKey(sym) ||
00256 IsMiscFunctionKey(sym) || IsPFKey(sym) ||
00257 IsPrivateKeypadKey(sym))
00258 {
00259 return;
00260 }
00261
00262 bool reset = false;
00263 if (event->state & ControlMask) {
00264 switch (sym) {
00265 case XK_H:
00266 case XK_h:
00267 sym = XK_BackSpace;
00268 break;
00269 case XK_J:
00270 case XK_j:
00271 sym = XK_Return;
00272 break;
00273 case XK_G:
00274 case XK_g:
00275 sym = XK_Escape;
00276 break;
00277 case XK_U:
00278 case XK_u:
00279 reset = true;
00280 break;
00281 }
00282 }
00283
00284 switch (sym) {
00285 case XK_BackSpace:
00286 removeChar();
00287 break;
00288 case XK_Right:
00289 selectNextEntry();
00290 break;
00291 case XK_Left:
00292 selectPrevEntry();
00293 break;
00294 case XK_Return:
00295 handlePressedReturn();
00296 break;
00297 case XK_Escape:
00298 escape();
00299 break;
00300 case XK_Num_Lock:
00301 break;
00302 default:
00303 if (reset) {
00304 text_ = "";
00305 queryText(text_);
00306 }
00307 else if ((count == 1) && !iscntrl(buffer[0])) {
00308 buffer[count] = 0;
00309 string text = "";
00310 if (home && (buffer[0] == '~')) {
00311 text = text_ + home;
00312 }
00313 else {
00314 text = text_ + buffer;
00315 }
00316 queryText(text);
00317 text_ = text;
00318 }
00319 else if (sym == XK_Tab) {
00320 string text = text_;
00321 if (!isNext) {
00322 queryText(text_);
00323 }
00324 isNext = (text == text_);
00325 if (isNext) {
00326 selectNextEntry();
00327 }
00328 }
00329 #ifdef POSIX_REGEX
00330 if (text_=="") {Binder::instance()->clearRegexPattern();}else{
00331 if (!names_.empty()) Binder::instance()->pushRegexPattern(text_);}
00332
00333 #endif
00334 break;
00335 }
00336 if (sym != XK_Tab) {
00337 isNext = false;
00338 }
00339 illuminate();
00340 }
00341
00342 void InputBar::escape() {
00343
00344 promptCounter_ = 0;
00345 args_ = "";
00346 prompt_ = 0;
00347 currAction_ = 0;
00348 #ifdef POSIX_REGEX
00349 Binder::instance()->clearRegexPattern();
00350 #endif
00351 XCORE->ungrabKeyboard();
00352 hide();
00353 }
00354
00355 void InputBar::handlePressedReturn() {
00356
00357 string actionKey;
00358 bool isDirectInvocation = false;
00359
00360 LOGDEBUG("fetching selection");
00361 actionKey = text();
00362 unsigned int pos = actionKey.find_first_of('+');
00363 if (!isArgument_ && (pos != string::npos)) {
00364 args_ = actionKey.substr(pos + 1);
00365 actionKey = actionKey.substr(0, pos);
00366 isDirectInvocation = true;
00367 }
00368 LOGDEBUG("selection fetched");
00369 if (isArgument_ || (actionKey != "") || isDirectInvocation) {
00370
00371 if (!isArgument_ || isDirectInvocation)
00372 {
00373 LOGDEBUG("fetching action: " + actionKey );
00374 currAction_ = Util::get(KERNEL->actionBindings(), actionKey);
00375 }
00376
00377 if (currAction_) {
00378
00379 if (!isArgument_ &&
00380 (currAction_->promptsCount() > 0) && !isDirectInvocation)
00381 {
00382
00383 prompt_ = currAction_->prompt(0);
00384 isArgument_ = true;
00385 queryText("");
00386 }
00387 else if (isArgument_) {
00388
00389
00390 if (args_.length() > 0) {
00391 args_ += '+';
00392 }
00393 args_ += text((currAction_->getToPerform() == &Actions::execute) ||
00394 (currAction_->getToPerform() == &Actions::executeTerm));
00395
00396 promptCounter_++;
00397 if (promptCounter_ < currAction_->promptsCount()) {
00398 prompt_ = currAction_->prompt(promptCounter_);
00399 }
00400 queryText("");
00401 }
00402 illuminate();
00403
00404 if ((promptCounter_ == currAction_->promptsCount()) ||
00405 isDirectInvocation)
00406 {
00407 LOGDEBUG("going to perform action");
00408 if (isArgument_ || isDirectInvocation) {
00409 LOGDEBUG("got args: " + args_);
00410 currAction_->setArgument((char *)args_.c_str());
00411 }
00412
00413 currAction_->perform();
00414 escape();
00415 }
00416 else {
00417 return;
00418 }
00419 }
00420 }
00421 }
00422
00423 void InputBar::runKey(Prompt *prompt) {
00424 if (!isVisible()) {
00425 show();
00426 }
00427 XCORE->grabKeyboard(window());
00428 currAction_ = 0;
00429 prompt_ = prompt;
00430 isArgument_ = false;
00431 queryText("");
00432 illuminate();
00433 }
00434
00435 void InputBar::runArgument(Action *action) {
00436 if (!action->isValid()) {
00437 return;
00438 }
00439 if (!isVisible()) {
00440 show();
00441 }
00442 XCORE->grabKeyboard(window());
00443 currAction_ = action;
00444
00445 prompt_ = currAction_->prompt(0);
00446 isArgument_ = true;
00447 queryText("");
00448 illuminate();
00449 }
00450
00451 void InputBar::handleMotionNotify(XMotionEvent *event) {
00452
00453 }
00454
00455 void InputBar::handleButtonPress(XButtonEvent *event) {
00456 escape();
00457 }
00458
00459 void InputBar::handleButtonRelease(XButtonEvent *event) {
00460
00461 }
00462
00463 bool InputBar::isArgument() const {
00464 return isArgument_;
00465 }