/android/import-contacts

To get this branch, use:
bzr branch http://bzr.ed.am/android/import-contacts

« back to all changes in this revision

Viewing changes to src/org/waxworlds/edam/importcontacts/FileChooser.java

  • Committer: edam
  • Date: 2009-01-13 06:35:26 UTC
  • Revision ID: edam@waxworlds.org-20090113063526-l9t1s9git4bav60a
- new contact's phone numebrs and email addresses are added to the caches after those contacts are updated to account for the situation where the same contact is imported again from another file (or the contact exists twice in the same file!?)

Show diffs side-by-side

added added

removed removed

1
 
/*
2
 
 * FileChooser.java
3
 
 *
4
 
 * Copyright (C) 2010 Tim Marston <edam@waxworlds.org>
5
 
 *
6
 
 * This file is part of the Import Contacts program (hereafter referred
7
 
 * to as "this program"). For more information, see
8
 
 * http://www.waxworlds.org/edam/software/android/import-contacts
9
 
 *
10
 
 * This program is free software: you can redistribute it and/or modify
11
 
 * it under the terms of the GNU General Public License as published by
12
 
 * the Free Software Foundation, either version 3 of the License, or
13
 
 * (at your option) any later version.
14
 
 *
15
 
 * This program is distributed in the hope that it will be useful,
16
 
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17
 
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18
 
 * GNU General Public License for more details.
19
 
 *
20
 
 * You should have received a copy of the GNU General Public License
21
 
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
22
 
 */
23
 
 
24
 
package org.waxworlds.edam.importcontacts;
25
 
 
26
 
import java.io.File;
27
 
import java.io.FileFilter;
28
 
import java.util.ArrayList;
29
 
import java.util.Collections;
30
 
import java.util.Comparator;
31
 
 
32
 
import android.app.AlertDialog;
33
 
import android.app.Dialog;
34
 
import android.content.Context;
35
 
import android.content.DialogInterface;
36
 
import android.view.LayoutInflater;
37
 
import android.view.View;
38
 
import android.view.View.OnClickListener;
39
 
import android.view.ViewGroup;
40
 
import android.widget.AdapterView;
41
 
import android.widget.AdapterView.OnItemClickListener;
42
 
import android.widget.ArrayAdapter;
43
 
import android.widget.Button;
44
 
import android.widget.ImageView;
45
 
import android.widget.ListView;
46
 
import android.widget.TextView;
47
 
 
48
 
public class FileChooser
49
 
{
50
 
        // pick an existing directory
51
 
        public final static int MODE_DIR = 1;
52
 
 
53
 
        // pick an existing file
54
 
        public final static int MODE_FILE = 2;
55
 
 
56
 
 
57
 
        private Dialog _dialog;
58
 
 
59
 
        // mode
60
 
        private int _mode = MODE_DIR;
61
 
 
62
 
        // ok was pressed
63
 
        boolean _ok = false;
64
 
 
65
 
        // working path
66
 
        private String _path;
67
 
 
68
 
        // selected filename
69
 
        private String _filename;
70
 
 
71
 
        // enforce extension (in file-mode)
72
 
        private String[] _extensions;
73
 
 
74
 
        // path to secretly prefix all paths with
75
 
        private String _path_prefix = "";
76
 
 
77
 
        private Context _context;
78
 
        private ArrayList< RowItem > _items;
79
 
        private DialogInterface.OnDismissListener _on_dismiss_listener;
80
 
 
81
 
        // class that represents a row in the list
82
 
        private class RowItem implements Comparable< RowItem >
83
 
        {
84
 
                private String _name;
85
 
                private boolean _directory;
86
 
 
87
 
                public RowItem( String name, boolean directory )
88
 
                {
89
 
                        _name = name;
90
 
                        _directory = directory;
91
 
                }
92
 
 
93
 
                public String getName()
94
 
                {
95
 
                        return _name;
96
 
                }
97
 
 
98
 
                public boolean isDirectory()
99
 
                {
100
 
                        return _directory;
101
 
                }
102
 
 
103
 
                @Override
104
 
                public int compareTo( RowItem that )
105
 
                {
106
 
                        if( this._directory && !that._directory )
107
 
                                return -1;
108
 
                        else if( !this._directory && that._directory )
109
 
                                return 1;
110
 
                        else
111
 
                                return this._name.compareToIgnoreCase( that._name );
112
 
                }
113
 
        }
114
 
 
115
 
        // class to manage our list of RowItems
116
 
        private class RowItemAdapter extends ArrayAdapter< RowItem >
117
 
        {
118
 
                private ArrayList< RowItem > _items;
119
 
 
120
 
                public RowItemAdapter( Context context, int textview_resource_id,
121
 
                        ArrayList< RowItem > items )
122
 
                {
123
 
                        super( context, textview_resource_id, items );
124
 
                        _items = items;
125
 
                }
126
 
 
127
 
                @Override
128
 
                public View getView( int position, View convert_view, ViewGroup parent )
129
 
                {
130
 
                        View view = convert_view;
131
 
                        if( view == null ) {
132
 
                                LayoutInflater factory = LayoutInflater.from( _context );
133
 
                                view = factory.inflate(  R.layout.filechooser_row, null );
134
 
                        }
135
 
                        RowItem rowitem = _items.get( position );
136
 
                        if( rowitem != null ) {
137
 
                                ( (TextView)view.findViewById( R.id.name ) )
138
 
                                        .setText( rowitem.getName() );
139
 
                                ( (ImageView)view.findViewById( R.id.icon ) ).setVisibility(
140
 
                                        rowitem.isDirectory()? View.VISIBLE : View.GONE );
141
 
                        }
142
 
                        return view;
143
 
                }
144
 
        }
145
 
 
146
 
        @SuppressWarnings( "serial" )
147
 
        class InvalidPathPrefixException extends RuntimeException
148
 
        {
149
 
        }
150
 
 
151
 
 
152
 
 
153
 
        // constructor
154
 
        public FileChooser( Context context )
155
 
        {
156
 
                _context = context;
157
 
        }
158
 
 
159
 
        public void setMode( int mode )
160
 
        {
161
 
                _mode = mode;
162
 
        }
163
 
 
164
 
        public void setPath( String path )
165
 
        {
166
 
                _path = cleanUpPath( path );
167
 
                File file = new File( _path_prefix + path.trim() );
168
 
 
169
 
                // path and filename
170
 
                if( file.isFile() ) {
171
 
                        _path = _path.substring( 0, _path.length() - 1 );
172
 
                        _filename = _path.substring( _path.lastIndexOf( '/' ) + 1 );
173
 
                        _path = _path.substring( 0, _path.length() - _filename.length() );
174
 
                }
175
 
 
176
 
                // else, treat as just a path
177
 
                else
178
 
                        _filename = "";
179
 
        }
180
 
 
181
 
        public void setExtensions( String[] extensions )
182
 
        {
183
 
                _extensions = extensions;
184
 
        }
185
 
 
186
 
        // set dismiss listener
187
 
        public void setDismissListener(
188
 
                DialogInterface.OnDismissListener on_dismiss_listener )
189
 
        {
190
 
                _on_dismiss_listener = on_dismiss_listener;
191
 
        }
192
 
 
193
 
        // set the path prefix
194
 
        public void setPathPrefix( String path_prefix )
195
 
        {
196
 
                // set to cleaned-up path, with trailing '/' removed so that it can be
197
 
                // trivially pre-pended to a cleaned-up path
198
 
                _path_prefix = cleanUpPath( path_prefix );
199
 
                _path_prefix = _path_prefix.substring( 0, _path_prefix.length() - 1 );
200
 
        }
201
 
 
202
 
        public boolean getOk()
203
 
        {
204
 
                return _ok;
205
 
        }
206
 
 
207
 
        public String getPath()
208
 
        {
209
 
                return _path + _filename;
210
 
        }
211
 
 
212
 
        public Dialog onCreateDialog()
213
 
        {
214
 
                // custom layout in an AlertDialog
215
 
                LayoutInflater factory = LayoutInflater.from( _context );
216
 
                final View dialogView = factory.inflate(
217
 
                        R.layout.filechooser, null );
218
 
 
219
 
                // wire up buttons
220
 
                ( (Button)dialogView.findViewById( R.id.ok ) )
221
 
                        .setOnClickListener( _fileChooserButtonListener );
222
 
                ( (ListView)dialogView.findViewById( R.id.list ) )
223
 
                        .setOnItemClickListener( _fileChooserItemClickListener );
224
 
 
225
 
                // return dialog
226
 
                Dialog dialog = new AlertDialog.Builder( _context )
227
 
                        .setTitle( " " )
228
 
                        .setView( dialogView )
229
 
                        .create();
230
 
                dialog.setOnDismissListener( _on_dismiss_listener );
231
 
                return dialog;
232
 
        }
233
 
 
234
 
        private OnClickListener _fileChooserButtonListener = new OnClickListener() {
235
 
                public void onClick( View view )
236
 
                {
237
 
                        switch( view.getId() )
238
 
                        {
239
 
                        case R.id.ok:
240
 
                                // close dialog and free (don't keep a reference)
241
 
                                _ok = true;
242
 
                                _dialog.dismiss();
243
 
                                break;
244
 
                        }
245
 
                }
246
 
        };
247
 
 
248
 
        private OnItemClickListener _fileChooserItemClickListener = new OnItemClickListener() {
249
 
                public void onItemClick( AdapterView< ? > adapter_view, View view, int position, long id )
250
 
                {
251
 
                        RowItem rowitem = _items.get( position );
252
 
 
253
 
                        // handle directory changes
254
 
                        if( rowitem.isDirectory() )
255
 
                        {
256
 
                                String dirname = rowitem.getName();
257
 
                                if( dirname.equals( ".." ) )
258
 
                                        strtipLastFilepartFromPath();
259
 
                                else
260
 
                                        _path += dirname + "/";
261
 
                                _filename = "";
262
 
 
263
 
                                updateList();
264
 
                        }
265
 
 
266
 
                        // handle file selections
267
 
                        else
268
 
                        {
269
 
                                _filename = rowitem.getName();
270
 
                                updateCurrentSelection();
271
 
                        }
272
 
                }
273
 
        };
274
 
 
275
 
        public void onPrepareDialog( Context context, Dialog dialog )
276
 
        {
277
 
                // set up reference to dialog
278
 
                _dialog = dialog;
279
 
                _context = context;
280
 
 
281
 
                // reset "ok"
282
 
                _ok = false;
283
 
 
284
 
                // pick text based on mode
285
 
                int title = 0, current = 0;
286
 
                switch( _mode ) {
287
 
                case MODE_DIR:
288
 
                        title = R.string.filechooser_title_dir;
289
 
                        current = R.string.filechooser_current_dir;
290
 
                        break;
291
 
                case MODE_FILE:
292
 
                        title = R.string.filechooser_title_file;
293
 
                        current = R.string.filechooser_current_file;
294
 
                        break;
295
 
                }
296
 
                dialog.setTitle( title );
297
 
                ( (TextView)dialog.findViewById( R.id.current ) )
298
 
                        .setText( _context.getString(  current ) );
299
 
 
300
 
                // clear filename in directory mode
301
 
                if( _mode == MODE_DIR )
302
 
                        _filename = "";
303
 
 
304
 
                // set root path icon
305
 
                ( (ImageView)_dialog.findViewById( R.id.icon ) )
306
 
                        .setImageResource( pathIcon( cleanUpPath( _path_prefix ) ) );
307
 
 
308
 
                // setup current-path-specific stuff
309
 
                updateList();
310
 
        }
311
 
 
312
 
        public static String cleanUpPath( String path )
313
 
        {
314
 
                path = path.trim();
315
 
 
316
 
                // ensure it starts and ends in a '/'
317
 
                if( !path.startsWith( "/" ) ) path = "/" + path;
318
 
                if( !path.endsWith( "/" ) ) path += "/";
319
 
 
320
 
                return path;
321
 
        }
322
 
 
323
 
        public static int pathIcon( String path )
324
 
        {
325
 
                if( path.equals( "/sdcard/" ) )
326
 
                        return R.drawable.sdcard;
327
 
 
328
 
                return R.drawable.directory;
329
 
        }
330
 
 
331
 
        public String prettyPrint( String full_path, boolean return_full )
332
 
        {
333
 
                String path = full_path;
334
 
 
335
 
                // special names
336
 
                if( path.equals( "/sdcard/" ) )
337
 
                        return " " + _context.getString( R.string.filechooser_path_sdcard );
338
 
 
339
 
                // remove prefix, if present
340
 
                if( path.startsWith( _path_prefix + "/" ) )
341
 
                        path = path.substring( _path_prefix.length() );
342
 
 
343
 
                // unless path is "/", strip trailing "/".
344
 
                if( path.length() > 1 && path.endsWith( "/" ) )
345
 
                        path = path.substring( 0, path.length() - 1 );
346
 
 
347
 
                // if full path not required, strip off preceding directories
348
 
                if( !return_full ) {
349
 
                        int idx = path.lastIndexOf( "/" );
350
 
                        if( idx != -1 ) path = path.substring( idx + 1 );
351
 
                }
352
 
 
353
 
                return path;
354
 
        }
355
 
 
356
 
        protected void strtipLastFilepartFromPath()
357
 
        {
358
 
                int at = _path.lastIndexOf( '/', _path.length() - 2 );
359
 
                if( at != -1 ) _path = _path.substring( 0, at + 1 );
360
 
        }
361
 
 
362
 
        protected void updateList()
363
 
        {
364
 
                // reset item list
365
 
                _items = new ArrayList< RowItem >();
366
 
 
367
 
                // open directory (and ensure _path is a directory)
368
 
                File dir = new File( _path_prefix + _path );
369
 
                while( !dir.isDirectory() ) {
370
 
                        if( _path == "/" )
371
 
                                throw new InvalidPathPrefixException();
372
 
                        strtipLastFilepartFromPath();
373
 
                        dir = new File( _path_prefix + _path );
374
 
                }
375
 
 
376
 
                // add ".."?
377
 
                if( !_path.equals( "/" ) )
378
 
                        _items.add( new RowItem( "..", true ) );
379
 
 
380
 
                // get directories
381
 
                class DirFilter implements FileFilter {
382
 
                        public boolean accept( File file ) {
383
 
                                return file.isDirectory() && file.getName().charAt( 0 ) != '.';
384
 
                        }
385
 
                }
386
 
                File[] files = dir.listFiles( new DirFilter() );
387
 
                for( int i = 0; i < files.length; i++ )
388
 
                        _items.add( new RowItem( files[ i ].getName(), true ) );
389
 
 
390
 
                // get files
391
 
                if( _mode == MODE_FILE )
392
 
                {
393
 
                        class VCardFilter implements FileFilter {
394
 
                                public boolean accept( File file ) {
395
 
                                        if( file.isDirectory() || file.getName().startsWith( "." ) )
396
 
                                                return false;
397
 
                                        String filename = file.getName().toLowerCase();
398
 
                                        for( int i = 0; i < _extensions.length; i++ )
399
 
                                                if( filename.endsWith( "." + _extensions[ i ] ) )
400
 
                                                        return true;
401
 
                                        return false;
402
 
                                }
403
 
                        }
404
 
                        files = dir.listFiles( new VCardFilter() );
405
 
                        for( int i = 0; i < files.length; i++ )
406
 
                                _items.add( new RowItem( files[ i ].getName(), false ) );
407
 
                }
408
 
 
409
 
                // sort
410
 
                class RowItemSorter implements Comparator< RowItem > {
411
 
                        @Override
412
 
                        public int compare( RowItem lhs, RowItem rhs ) {
413
 
                                return lhs.compareTo( rhs );
414
 
                        }
415
 
                }
416
 
                Collections.sort( _items, new RowItemSorter() );
417
 
 
418
 
                // setup directory list
419
 
                ( (ListView)_dialog.findViewById( R.id.list ) ).setAdapter(
420
 
                        new RowItemAdapter( _context, R.layout.filechooser_row,
421
 
                                _items ) );
422
 
 
423
 
                updateCurrentSelection();
424
 
        }
425
 
 
426
 
        private void updateCurrentSelection()
427
 
        {
428
 
                // set current path
429
 
                ( (TextView)_dialog.findViewById( R.id.path ) ).setText(
430
 
                        prettyPrint( _path_prefix + _path + _filename, true ) );
431
 
 
432
 
                // enable/disable ok button
433
 
                if( _mode == MODE_FILE )
434
 
                        _dialog.findViewById( R.id.ok ).setEnabled( _filename != "" );
435
 
                else
436
 
                        _dialog.findViewById( R.id.ok ).setEnabled( true );
437
 
        }
438
 
 
439
 
}