Hatena::ブログ(Diary)

Pyro Memo RSSフィード

2011-10-28

[] CakePHPのViewで現在のURLを取得する

$html->url(null);

[] CakePHPflashメッセージを通知用とエラー用でデザインを変更する

コントローラで下記のようにsetFlashメソッドを呼び出す。

通知用、エラー用にそれぞれcssクラスを作って指定してやる。


//通知用
$this->setFlash("データを登録しました", "default", array("class" => "flash-notice"));

//エラー用
$this->setFlash("エラーが発生しました", "default", array("class" => "flash-error"));


下記のような感じでCSSを定義しておく


.flash-error {
    padding: 10px;
    margin: 15px auto;
    border: #FF6666 2px solid;
    background: #FFF0F0;
    color: #FF0000;
}

.flash-notice {
    padding: 10px;
    margin: 15px auto;
    border: #66CC66 2px solid;
    background: #F0FFF0;
    color: #008800;
}

2011-07-23

[] generic.xamlでカスタムコントロールのスタイルを定義する時の決まりごと

http://d.hatena.ne.jp/kaorun/20110323/1300874396

から学んだこと。


  1. generic.xamlはプロジェクトフォルダ直下にThemesフォルダを作成してそこに配置する
  2. カスタムコントロールのコンストラクタ内でDefaultStyleKeyを設定する

2011-07-07

[] SilverlightWebカメラの映像を表示する

こちらを参考に作成した。

http://msdn.microsoft.com/ja-jp/library/ff602282(v=vs.95).aspx


Webカメラに接続して映像を画面上に表示できるだけのサンプル。

BrushとしてRectangleのFillに設定してるので、Brushが設定できるところなら

どこでも映像を表示できるっぽい。

画像を切り出して保存もできるらしいので、色々面白いことできそうだなぁ。思いつかないけど。


MainPage.xaml

<UserControl x:Class="CameraTest.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d"
    d:DesignHeight="500" d:DesignWidth="600">

    <Grid x:Name="LayoutRoot" Background="White">
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto" />
            <RowDefinition Height="*" />
        </Grid.RowDefinitions>
        
        <Grid Grid.Row="0">
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="*" />
                <ColumnDefinition Width="Auto" />
                <ColumnDefinition Width="Auto" />
            </Grid.ColumnDefinitions>
            <ComboBox x:Name="Devices" Grid.Column="0">
                <ComboBox.ItemTemplate>
                    <DataTemplate>
                        <TextBlock Text="{Binding FriendlyName}" />
                    </DataTemplate>
                </ComboBox.ItemTemplate>
            </ComboBox>
            
            <Button Grid.Column="1" Content="Start" x:Name="StartButton" Click="StartButton_Click" />
            <Button Grid.Column="2" Content="Stop" x:Name="StopButton" Click="StopButton_Click" />
        </Grid>
        <Rectangle Grid.Row="1" x:Name="webcamDisplay" Width="150" Height="100" Stroke="Black" />
    </Grid>
</UserControl>

MainPage.xaml.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;

namespace CameraTest
{
    public partial class MainPage : UserControl
    {

        CaptureSource captureSource = new CaptureSource();

        public MainPage()
        {
            InitializeComponent();

            Devices.ItemsSource = CaptureDeviceConfiguration.GetAvailableVideoCaptureDevices();

            VideoBrush webcamBrush = new VideoBrush();
            webcamBrush.SetSource(captureSource);
            webcamDisplay.Fill = webcamBrush;
        }

        private void StartButton_Click(object sender, RoutedEventArgs e)
        {

            captureSource.VideoCaptureDevice = (VideoCaptureDevice)Devices.SelectedItem;

            if (CaptureDeviceConfiguration.RequestDeviceAccess() && captureSource.VideoCaptureDevice != null)
            {
                try
                {
                    captureSource.Start();
                }
                catch (InvalidOperationException ex)
                {
                    MessageBox.Show("カメラの起動に失敗しました");
                }
            }
        }

        private void StopButton_Click(object sender, RoutedEventArgs e)
        {
            if (captureSource.VideoCaptureDevice != null)
            {
                captureSource.Stop();
            }
        }
    }
}

[] Silverlightでファイルをアップロードして保存する

複数ファイルアップロードが結構簡単にできるみたい。

下記のサイトを参考(ほぼそのまま)に作ってみた。


Silverlight 4でドロップされたデータをサーバに保存

http://d.hatena.ne.jp/okazuki/20100330/1269949623


Silverlightでユーザがアップロードしたファイルをダウンロードする

http://d.hatena.ne.jp/coma2n/20080421/1208784501


ファイルを開くダイアログで選択された複数のファイルをサーバアップロードして保存するサンプル。

WCF RIA Servicesのドメインサービスを使ってサーバ側と連携してる。


MainPage.xaml

<UserControl x:Class="SilverFileUpload.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d"
    d:DesignHeight="300" d:DesignWidth="400">

    <StackPanel x:Name="LayoutRoot" Background="White">
        <Button x:Name="OpenFileButton" Content="open file" Click="OpenFileButton_Click" />
        <TextBox x:Name="MessageTextBox" Width="200" Margin="10" AcceptsReturn="True" Height="200" />
    </StackPanel>
</UserControl>

MainPage.xaml.cs

using System;
using System.Text;
using System.IO;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using SilverFileUpload.Web;

namespace SilverFileUpload
{
    public partial class MainPage : UserControl
    {
        public MainPage()
        {
            InitializeComponent();
        }

        private void OpenFileButton_Click(object sender, RoutedEventArgs e)
        {
            OpenFileDialog openFileDialog = new OpenFileDialog();
            openFileDialog.Filter = "Text Files (.txt)|*.txt|All Files (.*)|*.*";
            openFileDialog.FilterIndex = 1;
            openFileDialog.Multiselect = true;

            bool? isOKClicked = openFileDialog.ShowDialog();

            if (isOKClicked == true)
            {
                IEnumerable<FileInfo> files = openFileDialog.Files;
                StringBuilder sb = new StringBuilder();
                foreach (FileInfo file in files)
                {
                    using (var stream = file.OpenRead())
                    {
                        var ms = new MemoryStream();
                        byte[] buffer = new byte[1024 * 100];
                        while (stream.Read(buffer, 0, buffer.Length) != 0)
                        {
                            ms.Write(buffer, 0, buffer.Length);
                        }

                        var ctx = new FileUploadDomainContext();
                        ctx.Upload(file.Name, ms.ToArray(), result =>
                            {
                                // 終了後処理
                            }, null);
                    }
                    sb.Append(file.Name + "\r\n");
                }

                MessageTextBox.Text = sb.ToString();
            }
        }
    }
}

FileUploadDomainService.cs


namespace SilverFileUpload.Web
{
    using System;
    using System.IO;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.ComponentModel.DataAnnotations;
    using System.Linq;
    using System.ServiceModel.DomainServices.Hosting;
    using System.ServiceModel.DomainServices.Server;


    // TODO: アプリケーション ロジックを含むメソッドを作成します。
    [EnableClientAccess()]
    public class FileUploadDomainService : DomainService
    {

        public bool Upload(string fileName, byte[] data)
        {
            try
            {
                using (var w = new FileStream(Path.Combine(@"ファイル保存先ディレクトリ", fileName), FileMode.OpenOrCreate, FileAccess.Write))
                {
                    w.Write(data, 0, data.Length);
                }
                return true;
            }
            catch
            {
                return false;
            }
        }
    }
}

AppEngineでもサンプルを作ってみたいところ。

2011-07-06

[][] 指定したフォルダ内のファイルの文字コードUTF-8に変換するタスク

指定フォルダ内の全ファイルについて、文字コードを自動判定して読み込み、

UTF-8に変換して保存するカスタムタスクを作成する。


文字コード自動判定については、下記のページでJcode.pmを参考にした関数

紹介されているので、そちらを使わせていただく。

http://dobon.net/vb/dotnet/string/detectcode.html


紹介されているGetCode関数を、UtilsフォルダにJcode.csとして保存したとする。


作ったタスクはこんな感じ。

文字コードShift_JISEUC-JPの場合のみUTF-8に変換するようにしてる。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using NAnt.Core;
using NAnt.Core.Attributes;
using MyTasks.Utils;

namespace MyTasks.Tasks
{
    [TaskName("encode2utf8")]
    class Encode2UTF8Task : Task
    {

        private string _dirPath;

        [TaskAttribute("dir", Required = true)]
        [StringValidator(AllowEmpty = false)]
        public string DirPath
        {
            get { return this._dirPath; }
            set { this._dirPath = value; }
        }

        protected override void ExecuteTask()
        {
            System.IO.DirectoryInfo dirInfo = new System.IO.DirectoryInfo(this._dirPath);

            IEnumerable<System.IO.FileInfo> fileList = dirInfo.GetFiles("*.*", System.IO.SearchOption.AllDirectories);

            var queryMatchingFiles = from file in fileList
                                     select file.FullName;

            System.Text.Encoding enc_utf8 = System.Text.Encoding.GetEncoding("utf-8");

            System.Text.Encoding enc = null;
            System.IO.FileStream fs = null;
            byte[] bs = null;
            foreach (string fileName in queryMatchingFiles)
            {
                fs = new System.IO.FileStream(fileName, System.IO.FileMode.Open, System.IO.FileAccess.Read);
                bs = new byte[fs.Length];
                fs.Read(bs, 0, bs.Length);
                fs.Close();

                enc = Jcode.GetCode(bs);
                if (enc != null)
                {
                    if (enc.CodePage == 932 || enc.CodePage == 51932)
                    {
                        System.IO.File.WriteAllText(fileName, enc.GetString(bs), enc_utf8);
                        Log(Level.Info, string.Format("{0}から{1}に変換しました: {2}", enc.EncodingName, enc_utf8.EncodingName, fileName));
                    }
                }
            }
        }
    }
}

buildファイルにはこんな感じでタスクを定義する

  <target name="load">
    <loadtasks assembly="C:\ht\data\workspace\MyTasks\MyTasks\bin\Debug\MyTasks.dll" />
  </target>

  <target name="encode2utf8" depends="load">
    <if test="${not property::exists('dirPath')}">
      <property name="dirPath" value="${basic::getInput()}" />
    </if>
    <encode2utf8 dir="${dirPath}" />
  </target>

使う時は、コマンドプロンプトで下記のようなコマンドを実行する

nant encode2utf8 -D:dirPath=C:\sjis_folder

既存ファイルを上書きしちゃうので、使う時はご注意ください。

2011-07-05

[][] NAntのカスタムタスクで実行時にユーザー入力を受け付ける

便利タスクを作っていく上で、実行時に処理対象を指定したりできた方がいい、

ということでユーザー入力を受け付ける方法を調査した。


方法としては2つあって、どちらもプロパティ変数みたいなもの)に

ユーザーからの入力を代入するというもの。


  1. nantコマンド実行時に -D オプションプロパティ名と値を指定する
  2. ユーザー入力を受け付けるカスタムファンクションを作成する

1つ目の -D オプションによるプロパティ定義は、buildファイルにpropertyタグを書くのと同じ効果。

こんな感じで指定する

nant タスク名 -D:プロパティ名=プロパティ値
nant greetings -D:message=Hello!

これは、buildファイルに下記のタグを書くのと同じ。

<property name="message" value="Hello!" />

実行時に入力を受け付けるにはこれで十分なのだけど、せっかく調べたので

カスタムファンクションを作成する方法も書いておく。


どうやらNAntにはユーザー入力を受け付ける関数なりタスクは用意されていないようで、

自分でカスタムファンクションとしてユーザーに入力を促す処理を書くことで実現する。


入力処理についてはここを参考にした。

http://www.mail-archive.com/nant-users%40lists.sourceforge.net/msg11606.html


カスタムファンクションについては、ソースを見るのが一番良いようだけど、

ここからヒントをもらった。

http://efreedom.com/Question/1-284120/NAnt-Extension-Function-Project-Object


上記を参考にこんなクラスを作成。

using System.Collections.Generic;
using System.Linq;
using System.Text;
using NAnt.Core;
using NAnt.Core.Attributes;

namespace MyTasks.Funcs
{
    [FunctionSet("basic", "Basic")]
    class BasicFunctions : FunctionSetBase
    {
        public BasicFunctions(Project project, PropertyDictionary properties)
            :base(project, properties)
        {

        }

        [Function("getInput")]
        public static string GetInput()
        {
            Console.WriteLine("Enter a string:");
            string s = Console.ReadLine();
            return s.ToString();
        }
    }
}

buildファイルに下記のようなpropertyタグを作成すると、ユーザー入力を促して

プロパティ値に設定することができる。

<property name="message" value="${basic::getInput()}" />

この2つの入力方法を組み合わせて、コマンド実行時にプロパティを指定していなければ

ユーザー入力を促す、という処理を作成するとしたら、こんな感じでビルドファイルに定義する。

...
<target name="greetings" depends="load">
    <if test="${not property::exists('message')}">
      <property name="message" value="${basic::getInput()}" />
    </if>
    <greetings mesg="${message}" />
</target>
...