bool Console::PopulateInterpreter() { interpreters_->RemoveAllItems(); HashSet<Object*>* receivers = context_->GetEventReceivers(E_CONSOLECOMMAND); if (!receivers || receivers->Empty()) return false; Vector<String> names; for (HashSet<Object*>::ConstIterator iter = receivers->Begin(); iter != receivers->End(); ++iter) names.Push((*iter)->GetTypeName()); Sort(names.Begin(), names.End()); unsigned selection = M_MAX_UNSIGNED; for (unsigned i = 0; i < names.Size(); ++i) { const String& name = names[i]; if (name == commandInterpreter_) selection = i; Text* text = new Text(context_); text->SetStyle("ConsoleText"); text->SetText(name); interpreters_->AddItem(text); } const IntRect& border = interpreters_->GetPopup()->GetLayoutBorder(); interpreters_->SetMaxWidth(interpreters_->GetListView()->GetContentElement()->GetWidth() + border.left_ + border.right_); bool enabled = interpreters_->GetNumItems() > 1; interpreters_->SetEnabled(enabled); interpreters_->SetFocusMode(enabled ? FM_FOCUSABLE_DEFOCUSABLE : FM_NOTFOCUSABLE); if (selection == M_MAX_UNSIGNED) { selection = 0; commandInterpreter_ = names[selection]; } interpreters_->SetSelection(selection); return true; }
void Object::SendEvent(StringHash eventType, VariantMap& eventData) { if (!Thread::IsMainThread()) { LOGERROR("Sending events is only supported from the main thread"); return; } // Make a weak pointer to self to check for destruction during event handling WeakPtr<Object> self(this); Context* context = context_; HashSet<Object*> processed; context->BeginSendEvent(this); // Check first the specific event receivers const HashSet<Object*>* group = context->GetEventReceivers(this, eventType); if (group) { for (HashSet<Object*>::ConstIterator i = group->Begin(); i != group->End();) { HashSet<Object*>::ConstIterator current = i++; Object* receiver = *current; Object* next = 0; if (i != group->End()) next = *i; unsigned oldSize = group->Size(); receiver->OnEvent(this, eventType, eventData); // If self has been destroyed as a result of event handling, exit if (self.Expired()) { context->EndSendEvent(); return; } // If group has changed size during iteration (removed/added subscribers) try to recover /// \todo This is not entirely foolproof, as a subscriber could have been added to make up for the removed one if (group->Size() != oldSize) i = group->Find(next); processed.Insert(receiver); } } // Then the non-specific receivers group = context->GetEventReceivers(eventType); if (group) { if (processed.Empty()) { for (HashSet<Object*>::ConstIterator i = group->Begin(); i != group->End();) { HashSet<Object*>::ConstIterator current = i++; Object* receiver = *current; Object* next = 0; if (i != group->End()) next = *i; unsigned oldSize = group->Size(); receiver->OnEvent(this, eventType, eventData); if (self.Expired()) { context->EndSendEvent(); return; } if (group->Size() != oldSize) i = group->Find(next); } } else { // If there were specific receivers, check that the event is not sent doubly to them for (HashSet<Object*>::ConstIterator i = group->Begin(); i != group->End();) { HashSet<Object*>::ConstIterator current = i++; Object* receiver = *current; Object* next = 0; if (i != group->End()) next = *i; if (!processed.Contains(receiver)) { unsigned oldSize = group->Size(); receiver->OnEvent(this, eventType, eventData); if (self.Expired()) { context->EndSendEvent(); return; } if (group->Size() != oldSize) i = group->Find(next); } } } } context->EndSendEvent(); }