us.cboyd.android.dicom.DcmBrowser.java Source code

Java tutorial

Introduction

Here is the source code for us.cboyd.android.dicom.DcmBrowser.java

Source

/*
 * Copyright (C) 2013-2014 Christopher Boyd
 * 
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 * 
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 * 
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 * 
 */

package us.cboyd.android.dicom;

import java.io.File;
import java.util.ArrayList;

import org.opencv.android.BaseLoaderCallback;
import org.opencv.android.LoaderCallbackInterface;
import org.opencv.android.OpenCVLoader;

import us.cboyd.android.shared.ExternalIO;
import android.app.ActionBar;
import android.app.AlertDialog;
import android.app.Dialog;
import android.app.FragmentManager;
import android.app.FragmentTransaction;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.os.Bundle;
import android.os.Environment;
import android.support.v4.app.ActionBarDrawerToggle;
import android.support.v4.app.FragmentActivity;
import android.support.v4.view.GravityCompat;
import android.support.v4.widget.DrawerLayout;
import android.util.Log;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ListView;

/**
 * DICOM Browser
 * 
 * @author Christopher Boyd
 * @version 0.3
 *
 */
public class DcmBrowser extends FragmentActivity implements DcmListFragment.OnFileSelectedListener {

    private DcmListFragment mListFragment;
    private DcmInfoFragment mInfoFragment;

    // Drawer stuff
    private boolean mDrawerOpen = false;
    private boolean mFragmented = false;
    private DrawerLayout mDrawerLayout;
    private ListView mDrawerList;
    private ActionBarDrawerToggle mDrawerToggle = null;

    private CharSequence mDrawerTitle;
    private CharSequence mTitle;

    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.dcm_browser);

        FragmentManager fragManager = getFragmentManager();
        if (savedInstanceState != null) {
            mListFragment = (DcmListFragment) fragManager.getFragment(savedInstanceState, DcmVar.FRAGLIST);
            mInfoFragment = (DcmInfoFragment) fragManager.getFragment(savedInstanceState, DcmVar.FRAGINFO);

            // Remove existing fragments from associated views.
            fragManager.popBackStackImmediate(null, FragmentManager.POP_BACK_STACK_INCLUSIVE);
            fragManager.beginTransaction().remove(mListFragment).commit();
            fragManager.beginTransaction().remove(mInfoFragment).commit();
            fragManager.executePendingTransactions();
        }

        // Restore the retained fragments, if this is a configuration change.
        if (mListFragment == null) {
            mListFragment = new DcmListFragment();
        }

        if (mInfoFragment == null) {
            mInfoFragment = new DcmInfoFragment();
        }

        // Specify that the Home/Up button should not be enabled,
        // since there is no hierarchical parent yet.
        ActionBar actionBar = getActionBar();
        // enable ActionBar app icon to behave as action to toggle nav drawer
        actionBar.setDisplayHomeAsUpEnabled(false);
        actionBar.setHomeButtonEnabled(false);

        // Check whether the activity is using the layout version with
        // the fragment_container FrameLayout. If so, we must add the first fragment
        if (findViewById(R.id.fragment_container) != null) {
            Log.i("cpb", "mListFrag: One-pane");
            mFragmented = true;

            // Add the fragment to the 'fragment_container' FrameLayout
            fragManager.beginTransaction().add(R.id.fragment_container, mListFragment).commit();

            generateDrawer();
        } else {
            Log.i("cpb", "mListFrag: Two-pane");
            mFragmented = false;

            // Add the fragments to the respective FrameLayouts
            fragManager.beginTransaction().add(R.id.fragment_left, mListFragment).commit();
            fragManager.beginTransaction().add(R.id.fragment_right, mInfoFragment).commit();
        }
    }

    /** Called just before activity runs (after onStart). */
    @Override
    protected void onResume() {
        // If there isn't any external storage, quit the application.
        if (!ExternalIO.checkStorage()) {
            Resources res = getResources();

            AlertDialog.Builder builder = new AlertDialog.Builder(this);
            builder.setMessage(res.getString(R.string.err_mesg_disk))
                    .setTitle(res.getString(R.string.err_title_disk)).setCancelable(false)
                    .setPositiveButton(res.getString(R.string.err_close), new DialogInterface.OnClickListener() {
                        public void onClick(DialogInterface dialog, int id) {
                            DcmBrowser.this.finish();
                        }
                    });
            AlertDialog alertDialog = builder.create();
            alertDialog.show();

            // Else display data
        } else {
            mListFragment.setDir();
        }

        OpenCVLoader.initAsync(OpenCVLoader.OPENCV_VERSION_2_4_8, this, mLoaderCallback);
        super.onResume();
    }

    /** Called when orientation changes. */
    @Override
    public void onSaveInstanceState(Bundle outState) {
        FragmentManager fragManager = getFragmentManager();
        // If the fragment hasn't already been added to the FragmentManager, add it.
        // Otherwise, it can't be put in the Bundle.
        if (!mInfoFragment.isAdded()) {
            fragManager.beginTransaction().add(mInfoFragment, null).commit();
        }

        super.onSaveInstanceState(outState);
        outState.putString(DcmVar.CURRDIR, mListFragment.getDir().getAbsolutePath());
        fragManager.putFragment(outState, DcmVar.FRAGLIST, mListFragment);
        fragManager.putFragment(outState, DcmVar.FRAGINFO, mInfoFragment);
    }

    ////openCV
    private BaseLoaderCallback mLoaderCallback = new BaseLoaderCallback(this) {
        @Override
        public void onManagerConnected(int status) {
            switch (status) {
            case LoaderCallbackInterface.SUCCESS: {
                Resources res = getResources();
                Log.i(res.getString(R.string.tag_ocv), res.getString(R.string.ocv_load));
            }
                break;
            default: {
                super.onManagerConnected(status);
            }
                break;
            }
        }
    };

    @Override
    public void onBackPressed() {
        File temp = mListFragment.getDir();
        if (!mListFragment.isVisible()) {
            // Assume we're jumping back to the ListFragment
            if (ExternalIO.isRoot(temp)) {
                ActionBar actionBar = getActionBar();
                actionBar.setHomeButtonEnabled(false);
                actionBar.setDisplayHomeAsUpEnabled(false);
            }
            FragmentManager fm = getFragmentManager();
            if (fm.getBackStackEntryCount() > 0) {
                fm.popBackStack();
            } else {
                super.onBackPressed();
            }

            // If the directory is the external storage directory or there is no parent,
            // super.onBackPressed(). Else go to parent directory.
        } else if (ExternalIO.isRoot(temp)) {
            super.onBackPressed();
        } else {
            temp = temp.getParentFile();
            mListFragment.setDir(temp);
        }
        onDirectorySelected(temp);
    }

    /** onOptionsItemSelected responds to action bar item */
    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        // The action bar home/up action should open or close the drawer.
        // ActionBarDrawerToggle will take care of this.
        if (!mListFragment.isVisible() && mDrawerToggle.onOptionsItemSelected(item)) {
            return true;
        }
        switch (item.getItemId()) {
        // Respond to the action bar's Up/Home button
        case android.R.id.home:
            return navigateUp();
        }
        return super.onOptionsItemSelected(item);
    }

    /** navigateUp replicates "Back" functionality for the Home/Up key. */
    public boolean navigateUp() {
        File temp = mListFragment.getDir();
        if (mListFragment.isVisible()) {
            if (ExternalIO.isRoot(temp)) {
                ActionBar actionBar = getActionBar();
                actionBar.setHomeButtonEnabled(false);
                actionBar.setDisplayHomeAsUpEnabled(false);
                return false;
            } else {
                temp = temp.getParentFile();
                mListFragment.setDir(temp);
            }
        }
        onDirectorySelected(temp);
        return true;
    }

    /** onCreateOptionsMenu generates an options menu on the action bar */
    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        MenuInflater inflater = getMenuInflater();
        inflater.inflate(R.menu.dcm_main, menu);
        // Need to manually add icons to the Options menu above API v11
        //menu.getItem(R.id.about).setIcon(R.drawable.ic_action_about);
        return true;
    }

    /** onMenuItemSelected handles if something from the options menu is selected */
    @Override
    public boolean onMenuItemSelected(int featureId, MenuItem item) {

        switch (item.getItemId()) {

        case R.id.app_about:
            Dialog dialog = new Dialog(this);
            dialog.setContentView(R.layout.dialog_about);
            dialog.setTitle(getResources().getString(R.string.app_name));
            dialog.show();
            return true;

        case R.id.show_hidden:
            item.setChecked(!item.isChecked());
            mListFragment.setHidden(item.isChecked());
            return true;

        case R.id.show_info:
            item.setChecked(!item.isChecked());
            mInfoFragment.refreshTagList(item.isChecked());
            return true;

        case R.id.debug_mode:
            item.setChecked(!item.isChecked());
            mInfoFragment.changeMode(item.isChecked());
            return true;

        default:
            return super.onMenuItemSelected(featureId, item);

        }

    }

    public String getFolderTitle(File currDir) {
        if (currDir.equals(Environment.getExternalStorageDirectory())) {
            return getResources().getString(R.string.app_name);
        } else {
            return currDir.getName();
        }
    }

    public void onDirectorySelected(File currDir) {
        mDrawerTitle = getFolderTitle(currDir);
        getActionBar().setTitle(mDrawerTitle);

        if (!mListFragment.isVisible()) {
            // set up the drawer's list view with items and click listener
            mDrawerList.setAdapter(mListFragment.getListAdapter());
        }
    }

    public void onFileSelected(int position, ArrayList<String> fileList, File currDir) {
        // The user selected a DICOM file from the DcmListFragment
        position -= 1;
        if ((position < 0) || (position > fileList.size())) {
            // TODO: Error
            return;
        }

        if (mFragmented && mListFragment.isVisible()) {
            // If we're in the one-pane layout and need to swap fragments

            // Enable the Home/Up button to allow the user to go back to 
            ActionBar actionBar = getActionBar();
            actionBar.setHomeButtonEnabled(true);
            actionBar.setDisplayHomeAsUpEnabled(true);

            // Create fragment and give it an argument for the selected article
            Bundle args = new Bundle();
            args.putInt(DcmVar.POSITION, position);
            args.putStringArrayList(DcmVar.FILELIST, fileList);
            args.putString(DcmVar.CURRDIR, currDir.getPath());
            mInfoFragment.setArguments(args);
            FragmentTransaction transaction = getFragmentManager().beginTransaction();

            // Replace whatever is in the fragment_container view with this fragment,
            // and add the transaction to the back stack so the user can navigate back
            transaction.replace(R.id.fragment_container, mInfoFragment);
            transaction.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN);
            transaction.addToBackStack(null).commit();

            // set up the drawer's list view with items and click listener
            mDrawerList.setAdapter(mListFragment.getListAdapter());
        } else {
            // If we're in the two-pane layout or already displaying the DcmInfoFragment

            // Call a method in the DcmInfoFragment to update its content
            mInfoFragment.updateDicomInfo(position, fileList, currDir.getPath());
        }
        setTitle(fileList.get(position));
    }

    /** Load the current DICOM series */
    public void load(View view) {
        // Open the DICOM Viewer
        Intent intent = new Intent(this, DcmViewer.class);
        intent.putExtra(DcmVar.DCMFILE, mInfoFragment.getDicomFile());
        intent.putExtra(DcmVar.FILELIST, (ArrayList<String>) mInfoFragment.getFileList());
        startActivity(intent);
    }

    // Drawer stuff
    /* Called whenever we call invalidateOptionsMenu() */
    @Override
    public boolean onPrepareOptionsMenu(Menu menu) {
        // If the nav drawer is open, hide action items related to the content view
        if (mFragmented)
            mDrawerOpen = mDrawerLayout.isDrawerOpen(mDrawerList);
        //menu.findItem(R.id.action_websearch).setVisible(!drawerOpen);
        return super.onPrepareOptionsMenu(menu);
    }

    private void generateDrawer() {
        // Drawer stuff
        mDrawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
        mDrawerList = (ListView) findViewById(R.id.left_drawer);

        // set a custom shadow that overlays the main content when the drawer opens
        mDrawerLayout.setDrawerShadow(R.drawable.drawer_shadow, GravityCompat.START);
        // set up the drawer's list view with items and click listener
        /*mDrawerList.setAdapter(new ArrayAdapter<String>(this,
            R.layout.drawer_list_item, mPlanetTitles));*/
        mDrawerList.setOnItemClickListener(new DrawerItemClickListener());

        // ActionBarDrawerToggle ties together the the proper interactions
        // between the sliding drawer and the action bar app icon
        mDrawerToggle = new ActionBarDrawerToggle(this, /* host Activity */
                mDrawerLayout, /* DrawerLayout object */
                R.drawable.ic_drawer, /* nav drawer image to replace 'Up' caret */
                R.string.drawer_open, /* "open drawer" description for accessibility */
                R.string.drawer_close /* "close drawer" description for accessibility */
        ) {
            public void onDrawerClosed(View view) {
                getActionBar().setTitle(mTitle);
                invalidateOptionsMenu(); // creates call to onPrepareOptionsMenu()
            }

            public void onDrawerOpened(View drawerView) {
                getActionBar().setTitle(mDrawerTitle);
                invalidateOptionsMenu(); // creates call to onPrepareOptionsMenu()
            }
        };
        mDrawerLayout.setDrawerListener(mDrawerToggle);
    }

    /* The click listener for ListView in the navigation drawer */
    private class DrawerItemClickListener implements ListView.OnItemClickListener {
        @Override
        public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
            mListFragment.setSelection(position);
        }
    }

    @Override
    public void setTitle(CharSequence title) {
        mTitle = title;
        getActionBar().setTitle(mTitle);
    }

    /**
     * When using the ActionBarDrawerToggle, you must call it during
     * onPostCreate() and onConfigurationChanged()...
     */

    @Override
    protected void onPostCreate(Bundle savedInstanceState) {
        super.onPostCreate(savedInstanceState);
        // Sync the toggle state after onRestoreInstanceState has occurred.
        if (mFragmented) {
            if (mDrawerToggle == null) {
                generateDrawer();
            }
            mDrawerToggle.syncState();
        }
    }

    @Override
    public void onConfigurationChanged(Configuration newConfig) {
        super.onConfigurationChanged(newConfig);
        // Pass any configuration change to the drawer toggles
        if (mFragmented)
            mDrawerToggle.onConfigurationChanged(newConfig);
    }
}