001/*
002 * Copyright 2010-2015 Institut Pasteur.
003 * 
004 * This file is part of Icy.
005 * 
006 * Icy is free software: you can redistribute it and/or modify
007 * it under the terms of the GNU General Public License as published by
008 * the Free Software Foundation, either version 3 of the License, or
009 * (at your option) any later version.
010 * 
011 * Icy is distributed in the hope that it will be useful,
012 * but WITHOUT ANY WARRANTY; without even the implied warranty of
013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
014 * GNU General Public License for more details.
015 * 
016 * You should have received a copy of the GNU General Public License
017 * along with Icy. If not, see <http://www.gnu.org/licenses/>.
018 */
019package plugins.kernel.searchprovider;
020
021import icy.action.ActionManager;
022import icy.action.IcyAbstractAction;
023import icy.resource.icon.IcyIcon;
024import icy.search.SearchResult;
025import icy.search.SearchResultConsumer;
026import icy.search.SearchResultProducer;
027import icy.util.StringUtil;
028
029import java.awt.Image;
030import java.util.ArrayList;
031
032import org.pushingpixels.flamingo.api.common.RichTooltip;
033
034/**
035 * This class is used to provide kernel command elements to the search engine.
036 * 
037 * @author Stephane
038 */
039public class KernelSearchResultProducer extends SearchResultProducer
040{
041    public static class KernelSearchResult extends SearchResult
042    {
043        private final IcyAbstractAction action;
044        private final int priority;
045        private String description;
046
047        public KernelSearchResult(SearchResultProducer provider, IcyAbstractAction action, String searchWords[],
048                int priority)
049        {
050            super(provider);
051
052            this.action = action;
053            this.priority = priority;
054
055            final String longDesc = action.getLongDescription();
056
057            if (!StringUtil.isEmpty(longDesc))
058            {
059                final String[] lds = longDesc.split("\n");
060
061                if (lds.length > 0)
062                    // no more than 80 characters for description
063                    description = StringUtil.limit(lds[0], 80, true);
064
065                // highlight search keywords (only for more than 2 characters search)
066                if ((searchWords.length > 1) || (searchWords[0].length() > 2))
067                {
068                    // highlight search keywords in description
069                    for (String word : searchWords)
070                        description = StringUtil.htmlBoldSubstring(description, word, true);
071                }
072            }
073            else
074                description = "";
075        }
076
077        public IcyAbstractAction getAction()
078        {
079            return action;
080        }
081
082        @Override
083        public Image getImage()
084        {
085            final IcyIcon icon = action.getIcon();
086
087            if (icon != null)
088                return icon.getImage();
089
090            return null;
091        }
092
093        @Override
094        public String getTitle()
095        {
096            final String desc = action.getDescription();
097
098            if (!StringUtil.isEmpty(desc))
099                return desc;
100
101            return action.getName();
102        }
103
104        @Override
105        public String getDescription()
106        {
107            return description;
108        }
109
110        @Override
111        public String getTooltip()
112        {
113            if (isEnabled())
114                return "Click to execute the action";
115
116            return "Inactive action";
117            // return action.getLongDescription();
118        }
119
120        @Override
121        public boolean isEnabled()
122        {
123            return action.isEnabled();
124        }
125
126        @Override
127        public void execute()
128        {
129            action.execute();
130        }
131
132        @Override
133        public RichTooltip getRichToolTip()
134        {
135            final String longDesc = action.getLongDescription();
136
137            if (!StringUtil.isEmpty(longDesc))
138            {
139                if (longDesc.split("\n").length > 1)
140                    return action.getRichToolTip();
141            }
142
143            return null;
144        }
145
146        @Override
147        public void executeAlternate()
148        {
149            // nothing to do here...
150        }
151
152        @Override
153        public int compareTo(SearchResult o)
154        {
155            if (o instanceof KernelSearchResult)
156                return ((KernelSearchResult) o).priority - priority;
157
158            return super.compareTo(o);
159        }
160    }
161
162    @Override
163    public int getOrder()
164    {
165        // should be first
166        return 0;
167    }
168
169    @Override
170    public String getName()
171    {
172        return "Command";
173    }
174
175    @Override
176    public String getTooltipText()
177    {
178        return "Result(s) from the internal commands and actions";
179    }
180
181    @Override
182    public void doSearch(String[] words, SearchResultConsumer consumer)
183    {
184        if (hasWaitingSearch())
185            return;
186
187        final ArrayList<SearchResult> tmpResults = new ArrayList<SearchResult>();
188        final boolean shortSearch = (words.length == 1) && (words[0].length() <= 2);
189
190        for (IcyAbstractAction action : ActionManager.actions)
191        {
192            // abort
193            if (hasWaitingSearch())
194                return;
195
196            // action match filter
197            final int prio = searchInAction(action, words, shortSearch);
198
199            if (prio > 0)
200                tmpResults.add(new KernelSearchResult(this, action, words, prio));
201        }
202
203        results = tmpResults;
204        consumer.resultsChanged(this);
205    }
206
207    public static int searchInAction(IcyAbstractAction action, String words[], boolean startWithOnly)
208    {
209        int result = 0;
210
211        // we accept action which contains all words only
212        for (String word : words)
213        {
214            final int r = searchInAction(action, word, startWithOnly);
215
216            // word not found ? --> reject
217            if (r == 0)
218                return 0;
219
220            result += r;
221        }
222
223        // return mean score
224        return result / words.length;
225    }
226
227    public static int searchInAction(IcyAbstractAction action, String word, boolean startWithOnly)
228    {
229        final String wordlc = word.trim().toLowerCase();
230        String text;
231
232        // text = action.getName();
233        // if (!StringUtil.isEmpty(text) && text.toLowerCase().startsWith(wordlc))
234        // return 10;
235        text = action.getDescription();
236        if (!StringUtil.isEmpty(text) && text.toLowerCase().startsWith(wordlc))
237            return 8;
238        text = action.getLongDescription();
239        if (!StringUtil.isEmpty(text) && text.toLowerCase().startsWith(wordlc))
240            return 5;
241
242        if (!startWithOnly)
243        {
244            // text = action.getName();
245            // if (!StringUtil.isEmpty(text) && text.toLowerCase().contains(wordlc))
246            // return 9;
247            text = action.getDescription();
248            if (!StringUtil.isEmpty(text) && text.toLowerCase().contains(wordlc))
249                return 7;
250            text = action.getLongDescription();
251            if (!StringUtil.isEmpty(text) && text.toLowerCase().contains(wordlc))
252                return 3;
253        }
254
255        return 0;
256    }
257}