Skip to content

Commit

Permalink
Add a generic search to button lists.
Browse files Browse the repository at this point in the history
This adds back the incremental search in the lists that was lost during the switch to MythUI. While the old search was only available in MythMusic and MythGame this is available in all button lists including those used in the buttontree.

You access the search dialog using the new SEARCH (CTRL+S) keybinding while a buttonlist has the focus. The dialog allows you to enter a search string and also has find next and previous buttons. By default the search will search all text areas in a button item which works OK in most cases but some of the more complex button items like the ones in the playback recording screen require that the search be narrowed down to one or two text areas so there is a new MythButtonList::SetSearchFields(QString) function that takes a comma separated list of fields that should be searched. For example on the recording play back screen you want to search the "titlesubtitle" text area so you would call m_playbackList->SetSearchFields("titlesubtitle").

By default the popup will be displayed at the position set in the popups window definition which on some screens may obscure the list you are trying to search. I think the best people to decide where the popup should be displayed are the theme creators so there is a new optional <searchposition> element that can be added to the buttonlist definition that overrides the default popup position -  for example <searchposition>-1,400</searchposition> will display the popup horizontally centered and 400 down when the search dialog is shown for a button list with that in its definition.

Bumps the api version so a full recompile is required.
  • Loading branch information
Paul Harrison committed Jan 19, 2011
1 parent ff1066f commit a796d8b
Show file tree
Hide file tree
Showing 5 changed files with 374 additions and 1 deletion.
2 changes: 1 addition & 1 deletion mythtv/libs/libmythdb/mythversion.h
Expand Up @@ -11,7 +11,7 @@
/// Update this whenever the plug-in API changes.
/// Including changes in the libmythdb, libmyth, libmythtv, libmythav* and
/// libmythui class methods used by plug-ins.
#define MYTH_BINARY_VERSION "0.25.20110103-1"
#define MYTH_BINARY_VERSION "0.25.20110119-1"

/** \brief Increment this whenever the MythTV network protocol changes.
*
Expand Down
2 changes: 2 additions & 0 deletions mythtv/libs/libmythui/mythmainwindow.cpp
Expand Up @@ -1064,6 +1064,8 @@ void MythMainWindow::InitKeys()
,"Copy text from textedit"), "Ctrl+C");
RegisterKey("Global", "PASTE", QT_TRANSLATE_NOOP("MythControls",
"Paste text into textedit"), "Ctrl+V");
RegisterKey("Global", "SEARCH", QT_TRANSLATE_NOOP("MythControls",
"Show incremental search dialog"), "Ctrl+S");

RegisterKey("Global", "0", QT_TRANSLATE_NOOP("MythControls","0"), "0");
RegisterKey("Global", "1", QT_TRANSLATE_NOOP("MythControls","1"), "1");
Expand Down
277 changes: 277 additions & 0 deletions mythtv/libs/libmythui/mythuibuttonlist.cpp
Expand Up @@ -13,6 +13,9 @@
#include "mythmainwindow.h"
#include "mythuistatetype.h"
#include "lcddevice.h"
#include "mythuibutton.h"
#include "mythuitext.h"
#include "mythuitextedit.h"

#define LOC QString("MythUIButtonList(%1): ").arg(objectName())
#define LOC_ERR QString("MythUIButtonList(%1), Error: ").arg(objectName())
Expand Down Expand Up @@ -71,6 +74,10 @@ void MythUIButtonList::Const(void)
m_bottomRows = 0;
m_lcdTitle = "";

m_searchPosition = MythPoint(-2, -2);
m_searchFields = "**ALL**";
m_searchStartsWith = false;

m_upArrow = m_downArrow = NULL;

m_buttontemplate = NULL;
Expand Down Expand Up @@ -2190,6 +2197,36 @@ bool MythUIButtonList::keyPressEvent(QKeyEvent *e)
if (item)
emit itemClicked(item);
}
else if (action == "SEARCH")
{
MythScreenStack *popupStack = GetMythMainWindow()->GetStack("popup stack");

SearchButtonListDialog *dlg = new SearchButtonListDialog(popupStack, "MythSearchListDialog", this, "");

if (dlg->Create())
{
if (m_searchPosition.x() != -2 || m_searchPosition.y() != -2)
{
int x = m_searchPosition.x();
int y = m_searchPosition.y();
QRect screenArea = GetMythMainWindow()->GetUIScreenRect();
QRect dialogArea = dlg->GetArea();

if (x == -1)
x = (screenArea.width() - dialogArea.width()) / 2;

if (y == -1)
y = (screenArea.height() - dialogArea.height()) / 2;

dlg->SetPosition(x, y);
}

popupStack->AddScreen(dlg);
}
else
delete dlg;
}

else
handled = false;
}
Expand Down Expand Up @@ -2369,6 +2406,10 @@ bool MythUIButtonList::ParseElement(
m_drawFromBottom = parseBool(element);
m_alignment |= Qt::AlignBottom;
}
else if (element.tagName() == "searchposition")
{
m_searchPosition = parsePoint(element);
}
else
{
return MythUIType::ParseElement(filename, element, showWarnings);
Expand Down Expand Up @@ -2428,6 +2469,9 @@ void MythUIButtonList::CopyFrom(MythUIType *base)
m_clearing = false;
m_selPosition = m_topPosition = m_itemCount = 0;

m_searchPosition = lb->m_searchPosition;
m_searchFields = lb->m_searchFields;

MythUIType::CopyFrom(base);

m_upArrow = dynamic_cast<MythUIStateType *>(GetChild("upscrollarrow"));
Expand Down Expand Up @@ -2520,6 +2564,82 @@ void MythUIButtonList::updateLCD(void)
lcddev->switchToMenu(menuItems, m_lcdTitle);
}

bool MythUIButtonList::Find(const QString &searchStr, bool startsWith)
{
m_searchStr = searchStr;
m_searchStartsWith = startsWith;
return DoFind(false, true);
}

bool MythUIButtonList::FindNext(void)
{
return DoFind(true, true);
}

bool MythUIButtonList::FindPrev(void)
{
return DoFind(true, false);
}

bool MythUIButtonList::DoFind(bool doMove, bool searchForward)
{
if (m_searchStr.isEmpty())
return true;

int startPos = GetCurrentPos();
int currPos = startPos;
bool found = false;

if (doMove)
{
if (searchForward)
{
currPos++;

if (currPos >= GetCount())
currPos = 0;
}
else
{
currPos--;

if (currPos < 0)
currPos = GetCount() - 1;
}
}

while (true)
{
found = GetItemAt(currPos)->FindText(m_searchStr, m_searchFields, m_searchStartsWith);

if (found)
{
SetItemCurrent(currPos);
return true;
}

if (searchForward)
{
currPos++;

if (currPos >= GetCount())
currPos = 0;
}
else
{
currPos--;

if (currPos < 0)
currPos = GetCount() - 1;
}

if (startPos == currPos)
break;
}

return false;
}

//////////////////////////////////////////////////////////////////////////////

MythUIButtonListItem::MythUIButtonListItem(MythUIButtonList* lbtype,
Expand Down Expand Up @@ -2633,6 +2753,70 @@ QString MythUIButtonListItem::GetText(const QString &name) const
return QString();
}

bool MythUIButtonListItem::FindText(const QString &searchStr, const QString &fieldList,
bool startsWith) const
{
if (fieldList.isEmpty())
{
if (startsWith)
return m_text.startsWith(searchStr, Qt::CaseInsensitive);
else
return m_text.contains(searchStr, Qt::CaseInsensitive);
}
else if (fieldList == "**ALL**")
{
if (startsWith)
{
if (m_text.startsWith(searchStr, Qt::CaseInsensitive))
return true;
}
else
{
if (m_text.contains(searchStr, Qt::CaseInsensitive))
return true;
}

QMap<QString, TextProperties>::const_iterator i = m_strings.constBegin();
while (i != m_strings.constEnd())
{
if (startsWith)
{
if (i.value().text.startsWith(searchStr, Qt::CaseInsensitive))
return true;
}
else
{
if (i.value().text.contains(searchStr, Qt::CaseInsensitive))
return true;
}

++i;
}
}
else
{
QStringList fields = fieldList.split(',', QString::SkipEmptyParts);
for (int x = 0; x < fields.count(); x++)
{
if (m_strings.contains(fields.at(x).trimmed()))
{
if (startsWith)
{
if (m_strings[fields.at(x)].text.startsWith(searchStr, Qt::CaseInsensitive))
return true;
}
else
{
if (m_strings[fields.at(x)].text.contains(searchStr, Qt::CaseInsensitive))
return true;
}
}
}
}

return false;
}

void MythUIButtonListItem::SetFontState(const QString &state,
const QString &name)
{
Expand Down Expand Up @@ -2974,3 +3158,96 @@ void MythUIButtonListItem::SetToRealButton(MythUIStateType *button, bool selecte

m_parent->ItemVisible(this);
}

//---------------------------------------------------------
// SearchButtonListDialog
//---------------------------------------------------------
SearchButtonListDialog::SearchButtonListDialog(MythScreenStack *parent, const char *name,
MythUIButtonList *parentList, QString searchText)
: MythScreenType(parent, name, false)
{
m_parentList = parentList;
m_searchText = searchText;
m_startsWith = false;
}

SearchButtonListDialog::~SearchButtonListDialog(void)
{
}

bool SearchButtonListDialog::Create(void)
{
if (!CopyWindowFromBase("MythSearchListDialog", this))
return false;

bool err = false;
UIUtilE::Assign(this, m_searchEdit, "searchedit", &err);
UIUtilE::Assign(this, m_prevButton, "prevbutton", &err);
UIUtilE::Assign(this, m_nextButton, "nextbutton", &err);
UIUtilW::Assign(this, m_searchState, "searchstate");

if (err)
{
VERBOSE(VB_IMPORTANT, "Cannot load screen 'MythSearchListDialog'");
return false;
}

m_searchEdit->SetText(m_searchText);

connect(m_searchEdit, SIGNAL(valueChanged()), SLOT(searchChanged()));
connect(m_prevButton, SIGNAL(Clicked()), SLOT(prevClicked()));
connect(m_nextButton, SIGNAL(Clicked()), SLOT(nextClicked()));

BuildFocusList();

return true;
}

bool SearchButtonListDialog::keyPressEvent(QKeyEvent *event)
{
QStringList actions;
bool handled = GetMythMainWindow()->TranslateKeyPress("Music", event, actions, false);

for (int i = 0; i < actions.size() && !handled; i++)
{
QString action = actions[i];
handled = true;

if (action == "0")
{
m_startsWith = !m_startsWith;
searchChanged();
}
else
handled = false;
}

if (!handled && MythScreenType::keyPressEvent(event))
handled = true;

return handled;
}

void SearchButtonListDialog::searchChanged(void)
{
bool found = m_parentList->Find(m_searchEdit->GetText(), m_startsWith);

if (m_searchState)
m_searchState->DisplayState(found ? "found" : "notfound");
}

void SearchButtonListDialog::nextClicked(void)
{
bool found = m_parentList->FindNext();

if (m_searchState)
m_searchState->DisplayState(found ? "found" : "notfound");
}

void SearchButtonListDialog::prevClicked(void)
{
bool found = m_parentList->FindPrev();

if (m_searchState)
m_searchState->DisplayState(found ? "found" : "notfound");
}

0 comments on commit a796d8b

Please sign in to comment.