/* * Copyright 2013-2015, Rene Gollent, rene@gollent.com. * Distributed under the terms of the MIT License. */ #include "SignalsConfigView.h" #include #include #include #include #include #include #include "table/TableColumns.h" #include "AppMessageCodes.h" #include "MessageCodes.h" #include "SignalDispositionEditWindow.h" #include "SignalDispositionMenu.h" #include "SignalDispositionTypes.h" #include "UiUtils.h" #include "UserInterface.h" enum { MSG_ADD_DISPOSITION_EXCEPTION = 'adex', MSG_EDIT_DISPOSITION_EXCEPTION = 'edex', MSG_REMOVE_DISPOSITION_EXCEPTION = 'rdex' }; struct SignalDispositionInfo { SignalDispositionInfo(int32 _signal, int32 _disposition) : signal(_signal), disposition(_disposition) { } int32 signal; int32 disposition; }; class SignalsConfigView::SignalDispositionModel : public TableModel { public: SignalDispositionModel(::Team* team) : fDispositions(), fTeam(team) { } virtual ~SignalDispositionModel() { } virtual int32 CountColumns() const { return 2; } virtual int32 CountRows() const { return fDispositions.CountItems(); } virtual bool GetValueAt(int32 rowIndex, int32 columnIndex, BVariant& value) { SignalDispositionInfo* info = fDispositions.ItemAt(rowIndex); if (info == NULL) return false; switch (columnIndex) { case 0: { BString tempValue; value.SetTo(UiUtils::SignalNameToString(info->signal, tempValue)); return true; } case 1: { value.SetTo(UiUtils::SignalDispositionToString( info->disposition), B_VARIANT_DONT_COPY_DATA); return true; } default: break; } return false; } bool SignalDispositionInfoAt(int32 rowIndex, SignalDispositionInfo*& _info) { _info = fDispositions.ItemAt(rowIndex); if (_info == NULL) return false; return true; } void Update(int32 signal, int32 disposition) { for (int32 i = 0; i < fDispositions.CountItems(); i++) { SignalDispositionInfo* info = fDispositions.ItemAt(i); if (info->signal == signal) { info->disposition = disposition; NotifyRowsChanged(i, 1); return; } } SignalDispositionInfo* info = new(std::nothrow) SignalDispositionInfo( signal, disposition); if (info == NULL) return; ObjectDeleter infoDeleter(info); if (!fDispositions.AddItem(info)) return; infoDeleter.Detach(); NotifyRowsAdded(fDispositions.CountItems() - 1, 1); } void Remove(int32 signal) { for (int32 i = 0; i < fDispositions.CountItems(); i++) { SignalDispositionInfo* info = fDispositions.ItemAt(i); if (info->signal == signal) { fDispositions.RemoveItemAt(i); delete info; NotifyRowsRemoved(i, 1); return; } } } status_t Init() { AutoLocker< ::Team> locker(fTeam); const SignalDispositionMappings& dispositions = fTeam->GetSignalDispositionMappings(); for (SignalDispositionMappings::const_iterator it = dispositions.begin(); it != dispositions.end(); ++it) { SignalDispositionInfo* info = new(std::nothrow) SignalDispositionInfo(it->first, it->second); if (info == NULL) return B_NO_MEMORY; ObjectDeleter infoDeleter(info); if (!fDispositions.AddItem(info)) return B_NO_MEMORY; infoDeleter.Detach(); } return B_OK; } private: typedef BObjectList DispositionList; private: DispositionList fDispositions; ::Team* fTeam; }; SignalsConfigView::SignalsConfigView(::Team* team, UserInterfaceListener* listener) : BGroupView(B_VERTICAL), fTeam(team), fListener(listener), fDefaultSignalDisposition(NULL), fDispositionExceptions(NULL), fAddDispositionButton(NULL), fEditDispositionButton(NULL), fRemoveDispositionButton(NULL), fDispositionModel(NULL), fEditWindow(NULL) { SetName("Signals"); fTeam->AddListener(this); } SignalsConfigView::~SignalsConfigView() { fTeam->RemoveListener(this); BMessenger(fEditWindow).SendMessage(B_QUIT_REQUESTED); } SignalsConfigView* SignalsConfigView::Create(::Team* team, UserInterfaceListener* listener) { SignalsConfigView* self = new SignalsConfigView(team, listener); try { self->_Init(); } catch (...) { delete self; throw; } return self; } void SignalsConfigView::AttachedToWindow() { fDefaultSignalDisposition->Menu()->SetTargetForItems(this); fAddDispositionButton->SetTarget(this); fEditDispositionButton->SetTarget(this); fRemoveDispositionButton->SetTarget(this); fEditDispositionButton->SetEnabled(false); fRemoveDispositionButton->SetEnabled(false); AutoLocker< ::Team> teamLocker(fTeam); _UpdateSignalConfigState(); BGroupView::AttachedToWindow(); } void SignalsConfigView::MessageReceived(BMessage* message) { switch (message->what) { case MSG_SIGNAL_DISPOSITION_EDIT_WINDOW_CLOSED: { fEditWindow = NULL; } case MSG_SET_DEFAULT_SIGNAL_DISPOSITION: { int32 disposition; if (message->FindInt32("disposition", &disposition) != B_OK) break; fListener->SetDefaultSignalDispositionRequested(disposition); break; } case MSG_ADD_DISPOSITION_EXCEPTION: case MSG_EDIT_DISPOSITION_EXCEPTION: { if (fEditWindow != NULL) { AutoLocker lock(fEditWindow); if (lock.IsLocked()) fEditWindow->Activate(true); } else { int32 signal = 0; if (message->what == MSG_EDIT_DISPOSITION_EXCEPTION) { TableSelectionModel* model = fDispositionExceptions->SelectionModel(); SignalDispositionInfo* info; if (fDispositionModel->SignalDispositionInfoAt( model->RowAt(0), info)) { signal = info->signal; } } try { fEditWindow = SignalDispositionEditWindow::Create(fTeam, signal, fListener, this); if (fEditWindow != NULL) fEditWindow->Show(); } catch (...) { // TODO: notify user } } break; } case MSG_REMOVE_DISPOSITION_EXCEPTION: { TableSelectionModel* model = fDispositionExceptions->SelectionModel(); for (int32 i = 0; i < model->CountRows(); i++) { SignalDispositionInfo* info; if (fDispositionModel->SignalDispositionInfoAt(model->RowAt(i), info)) { fListener->RemoveCustomSignalDispositionRequested( info->signal); } } break; } case MSG_SET_CUSTOM_SIGNAL_DISPOSITION: { int32 signal; int32 disposition; if (message->FindInt32("signal", &signal) == B_OK && message->FindInt32("disposition", &disposition) == B_OK) { fDispositionModel->Update(signal, disposition); } break; } case MSG_REMOVE_CUSTOM_SIGNAL_DISPOSITION: { int32 signal; if (message->FindInt32("signal", &signal) == B_OK) fDispositionModel->Remove(signal); break; } default: BGroupView::MessageReceived(message); break; } } void SignalsConfigView::CustomSignalDispositionChanged( const Team::CustomSignalDispositionEvent& event) { BMessage message(MSG_SET_CUSTOM_SIGNAL_DISPOSITION); message.AddInt32("signal", event.Signal()); message.AddInt32("disposition", event.Disposition()); BMessenger(this).SendMessage(&message); } void SignalsConfigView::CustomSignalDispositionRemoved( const Team::CustomSignalDispositionEvent& event) { BMessage message(MSG_REMOVE_CUSTOM_SIGNAL_DISPOSITION); message.AddInt32("signal", event.Signal()); BMessenger(this).SendMessage(&message); } void SignalsConfigView::TableSelectionChanged(Table* table) { TableSelectionModel* model = fDispositionExceptions->SelectionModel(); int32 rowCount = model->CountRows(); fEditDispositionButton->SetEnabled(rowCount == 1); fRemoveDispositionButton->SetEnabled(rowCount > 0); } void SignalsConfigView::_Init() { SignalDispositionMenu* dispositionMenu = new SignalDispositionMenu( "signalDispositionsMenu", new BMessage(MSG_SET_DEFAULT_SIGNAL_DISPOSITION)); BGroupView* customDispositionsGroup = new BGroupView(); BLayoutBuilder::Group<>(customDispositionsGroup, B_VERTICAL, 0.0) .SetInsets(B_USE_SMALL_INSETS) .Add(fDispositionExceptions = new Table("customDispositions", B_WILL_DRAW, B_FANCY_BORDER)) .AddGroup(B_HORIZONTAL) .SetInsets(B_USE_SMALL_INSETS) .AddGlue() .Add(fAddDispositionButton = new BButton("Add" B_UTF8_ELLIPSIS, new BMessage(MSG_ADD_DISPOSITION_EXCEPTION))) .Add(fEditDispositionButton = new BButton("Edit" B_UTF8_ELLIPSIS, new BMessage(MSG_EDIT_DISPOSITION_EXCEPTION))) .Add(fRemoveDispositionButton = new BButton("Remove", new BMessage(MSG_REMOVE_DISPOSITION_EXCEPTION))) .End(); BBox* dispositionsBox = new BBox("custom dispositions box"); dispositionsBox->AddChild(customDispositionsGroup); dispositionsBox->SetLabel("Custom dispositions"); BLayoutBuilder::Group<>(this, B_VERTICAL) .SetInsets(B_USE_DEFAULT_SPACING) .Add(fDefaultSignalDisposition = new BMenuField( "stopTypes", "Default disposition:", dispositionMenu)) .Add(dispositionsBox); dispositionMenu->SetLabelFromMarked(true); // columns fDispositionExceptions->AddColumn(new StringTableColumn(0, "Signal", 80, 40, 1000, B_TRUNCATE_END, B_ALIGN_LEFT)); fDispositionExceptions->AddColumn(new StringTableColumn(1, "Disposition", 200, 40, 1000, B_TRUNCATE_END, B_ALIGN_RIGHT)); fDispositionExceptions->SetExplicitMinSize(BSize(400.0, 200.0)); fDispositionModel = new SignalDispositionModel(fTeam); if (fDispositionModel->Init() != B_OK) { delete fDispositionModel; return; } fDispositionExceptions->SetTableModel(fDispositionModel); fDispositionExceptions->AddTableListener(this); } void SignalsConfigView::_UpdateSignalConfigState() { int32 defaultDisposition = fTeam->DefaultSignalDisposition(); fDefaultSignalDisposition->Menu()->ItemAt(defaultDisposition) ->SetMarked(true); }